是否在C#中调用空构造函数?

top*_*l32 4 c# constructor

给定一个空的构造函数,例如:

internal C()
{
}
Run Code Online (Sandbox Code Playgroud)

是否需要创建对象?它应该只包含一个返回操作,所以理论上它可以被丢弃,对吧?

注:很清楚,,对于每个类,一个隐含的构造函数存在.然而,这个问题的意图是; 如果CLR只调用具有return操作的构造函数.

Luc*_*ski 6

始终在对象实例化上调用构造函数,即使它是无参数且为空的.如果您不编写任何构造函数,编译器将为您隐式生成默认构造函数.

这是给你写一个构造函数的可能性以后,而无需重新编译任何调用代码.

由于这个原因,对象实例化总是调用构造函数,除了边缘情况FormatterServices.GetUninitializedObject,这是我知道的实例化对象而不调用构造函数的唯一方法(它用于序列化目的).

顺便说一下,newobjIL操作码(用于实例化一个新对象)显式地将构造函数作为输入参数:

newobj指令创建一个新对象或值类型的新实例.Ctor是一个元数据标记(必须标记为构造函数的methodref或methoddef),它指示要调用的构造函数的名称,类和签名.

newobj指令分配与ctor相关联的类的新实例,并根据需要将新实例中的所有字段初始化为0(正确类型)或空引用.然后它使用给定的参数和新创建的实例调用构造函数ctor.调用构造函数后,现在初始化的对象引用(类型O)将被压入堆栈.

因此,要创建的类型实际上是由构造函数标识来调用,而不是由类型标记本身标识,这使得构造函数是必需的.


既然你想知道JIT做了什么,这里是Release模式下的以下行的反汇编(SomeClass是一个带有空默认构造函数的类):

var inst = new SomeClass();
Run Code Online (Sandbox Code Playgroud)

64位:

000007FE95A30093  in          al,dx  
000007FE95A30094  and         byte ptr [rax-73h],cl  
000007FE95A30097  or          eax,0FFEE4014h  
000007FE95A3009C  call        000007FEF5062400  
000007FE95A300A1  mov         rbx,rax  
000007FE95A300A4  call        000007FEEC977A00  
Run Code Online (Sandbox Code Playgroud)

86:

00320050  push        ebp  
00320051  mov         ebp,esp  
00320053  push        esi  
00320054  mov         ecx,28380Ch  
00320059  call        002720D4  
0032005E  mov         esi,eax  
00320060  call        72EA2578  
00320065  mov         ecx,eax  
00320067  mov         eax,dword ptr [ecx]  
00320069  mov         eax,dword ptr [eax+2Ch]  
0032006C  call        dword ptr [eax+1Ch]  
Run Code Online (Sandbox Code Playgroud)

好吧,我对汇编代码不太熟悉,但x64版本执行两次调用.我想第一个是分配,第二个是构造函数调用,但我不确定(VS不会因为某些原因让我去这些地址).callx86代码中的第三个(间接)对我来说是一个惊喜,我不知道它是什么.