给出一个空构造函数,例如:
internal C()
{
}
是否需要创建对象?它应该只包含一个返回操作,所以理论上它可以被丢弃,对吧?
注意: me 很明显,对于每个类,都存在一个隐式构造函数。然而,这个问题的意图是;如果CLR调用只有return
操作的构造函数。
答案 0 :(得分:5)
构造函数始终在对象实例化时被调用,即使它是无参数且为空的。如果您不编写任何构造函数,编译器会为您隐式生成默认构造函数。
这是为了让您可以稍后在上编写构造函数,而无需重新编译任何调用代码。
对象实例化总是因为这个原因调用构造函数,除了像FormatterServices.GetUninitializedObject
之类的边缘情况,这是我知道实例化对象而不调用构造函数的唯一方法(它用于序列化目的)
顺便说一句,newobj
IL操作码(用于实例化新对象)显式地将构造函数作为输入参数:
newobj
指令创建新对象或值类型的新实例。 Ctor 是一个元数据标记(必须标记为构造函数的methodref或methoddef),它指示要调用的构造函数的名称,类和签名。
newobj
指令分配与 ctor 关联的类的新实例,并将新实例中的所有字段初始化为0
(正确类型)或null适当的参考。然后,它使用给定的参数以及新创建的实例调用构造函数 ctor 。调用构造函数后,现在初始化的对象引用(类型O)将被压入堆栈。
因此,要创建的类型实际上是由构造函数标识为,而不是类型标记本身,这使得构造函数成为必需的。
由于您想知道JIT的作用,以下是在发布模式下反汇编以下行(SomeClass
是一个具有空默认构造函数的类):
var inst = new SomeClass();
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
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]
好吧,我对汇编代码不太熟悉,但x64版本执行两次调用。我想第一个是分配,第二个是构造函数调用,但我不确定(VS因为某些原因不允许我去这些地址)。 x86代码中的第三个(间接)call
对我来说是一个惊喜,我不知道它是为了什么。
答案 1 :(得分:1)
不,构造函数应该不被丢弃,因为它似乎是该类的作者只是想从它的声明程序集中实例化它(通过将构造函数标记为{{ 1}})。
答案 2 :(得分:0)
不,如果您不提供,将隐式调用默认构造函数。创建对象时,将传递构造函数,nextobjpointer
指向当前对象引用。
答案 3 :(得分:0)
是的,它会在每个对象创建时被调用,因为它是默认构造函数。如果您没有任何其他参数化构造函数,则可以省略它,但如果您使用其他构造函数,则需要指定默认构造函数。有关详细信息,请参阅this
答案 4 :(得分:0)
如果你编写一个构造函数,那没关系。每次声明任何类的对象都会撤消构造函数。
现在您可以明确地使用此构造函数来完成一些工作。
或者您可以将其留空或甚至不要在课堂上写下来。
保持空白而不是编写构造函数是完全相似的。