我注意到C#编译器在ret
方法结束时生成void
指令:
.method private hidebysig static void Main(string[] args) cil managed
{
// method body
L_0030: ret
}
我已经为.NET编写了一个编译器,无论我是否发出ret
语句,它都能正常工作(我已经检查了生成的IL,而且它确实不在那里)。
我只是想知道:对ret
返回void
所需的方法是void
吗?它似乎对堆栈没有任何作用,所以我认为{{1}}方法完全没有必要,但是我想听一些对CLR有更多了解的人?
答案 0 :(得分:22)
根据C#标准(ECMA-334),方法定义如下:
方法是实现可由对象或类执行的计算或操作的成员。 方法有一个(可能是空的)形式参数列表,一个返回值(除非方法的返回类型是 void),是静态的或非静态的。
(ECMA-334; 8.7.3:方法)。
现在,CLI标准定义了以下内容:
不允许控制只是“通过”方法的结尾。所有路径都将终止 使用以下指令之一:ret,throw,jmp或(tail。后跟call,calli或callvirt)。
(ECMA-335; 12.4,6)
这意味着,在C#中,返回void
的方法不需要return语句。但是,由于C#编译器将C#代码编译为IL代码,这需要在方法结束时终止路径,因此它会发出ret
来结束该方法。
答案 1 :(得分:17)
确实需要使代码可以验证。否则PEVerify将输出以下错误消息:
[IL]:错误:[(filename):( methodname)] [offset 0x00000000]在方法结束时没有返回
答案 2 :(得分:8)
来自Ecma-335。 (12.4,6)
不允许控制只是“通过”方法的结尾。所有路径都将终止 使用以下指令之一:ret,throw,jmp或(tail。后跟call,calli或callvirt)。