Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are empty constructors called in C#?

Tags:

c#

constructor

Given an empty constructor such as:

internal C()
{
}

Is it called upon object creation? It should only contain a return operation, so in theory, it could be discarded, right?

Note: It is clear to me, that for each class, an implicit constructor exists. The intend of this question is however; if the CLR calls constructors with exclusively a return operation.

like image 830
toplel32 Avatar asked Mar 15 '23 20:03

toplel32


2 Answers

A constructor is always called on object instantiation, even if it's parameterless and empty. If you don't write any constructor, a default one is implicitly generated for you by the compiler.

This is to give you the possibility to write a constructor later on, without having to recompile any calling code.

Object instantiation always calls a constructor for this reason, except for edge cases like FormatterServices.GetUninitializedObject which is the only way I know of to instantiate an object without calling a constructor (it's used for serialization purposes).

By the way, the newobj IL opcode (which is used to instantiate a new object), explicitly takes a constructor as an input parameter:

The newobj instruction creates a new object or a new instance of a value type. Ctor is a metadata token (a methodref or methoddef that must be marked as a constructor) that indicates the name, class and signature of the constructor to call.

The newobj instruction allocates a new instance of the class associated with ctor and initializes all the fields in the new instance to 0 (of the proper type) or null references as appropriate. It then calls the constructor ctor with the given arguments along with the newly created instance. After the constructor has been called, the now initialized object reference (type O) is pushed on the stack.

So the type to create is actually identified by the constructor to call, not by the type token itself, which makes a constructor mandatory.


Since you want to know what the JIT does, here's the disassembly of the following line in Release mode (SomeClass is a class with an empty default constructor):

var inst = new SomeClass();

x64:

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  

x86:

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]  

Ok, I'm not really fluent with assembly code, but the x64 version performs two calls. I suppose the first one is the allocation and the second one is the constructor call, but I'm not sure about that (VS won't let me go to these addresses for some reason). That third (indirected) call in the x86 code is a surprise to me, I don't know what it's for.

like image 98
Lucas Trzesniewski Avatar answered Mar 25 '23 02:03

Lucas Trzesniewski


No, the constructor should not be discarded because it's seems like the author of the class intended it to be instantiated only from within its declaring assembly (by marking the constructor as internal).

like image 23
haim770 Avatar answered Mar 25 '23 01:03

haim770