给定一个空的构造函数,例如:
internal C()
{
}
Run Code Online (Sandbox Code Playgroud)
是否需要创建对象?它应该只包含一个返回操作,所以理论上它可以被丢弃,对吧?
注:很清楚,我,对于每个类,一个隐含的构造函数存在.然而,这个问题的意图是; 如果CLR只调用具有return操作的构造函数.
始终在对象实例化上调用构造函数,即使它是无参数且为空的.如果您不编写任何构造函数,编译器将为您隐式生成默认构造函数.
这是给你写一个构造函数的可能性以后,而无需重新编译任何调用代码.
由于这个原因,对象实例化总是调用构造函数,除了边缘情况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代码中的第三个(间接)对我来说是一个惊喜,我不知道它是什么.