What happens when a constuctor is called
Consider the following class
public class MyClass
{
public int myField = 4;
public MyClass()
{
this.myField = 5;
}
}
when we compile this class, we get an assembly with IL in it. The parameterless constructor gets converted into a method with the name .ctor
Now, if we see the IL that gets generated for this .ctor method, we might expect it to have IL opcodes to assign the value 5 to the myField field of the class.
However, we can see that there is a lot more in there.
First of all, we see IL commands to assign the value 4 to myField, then the .ctor method of System.Object gets called. Finally, we see the code within the MyClass’s constructor.
When we write code to instantiate this class using the new operator (i.e. MyClass myObject = new MyClass();) the following things happen in the given order: -
1. Execution of the initializers of all the class’s fields
2. Execution of the class’s base class constructor
3. Execution of the code within this class constructor
Let us create another class MyDerivedClass and derive it from MyClass as below.
public class MyDerivedClass : MyClass
{
public int myDerivedProperty = 6;
public MyDerivedClass()
{
this.myDerivedProperty = 7;
}
}
When we instantiate MyDerivedClass, by the same flow as earlier, the following things happen in order
1. myDerivedProperty gets initialized to 6
2. the constructor of MyClass gets called
a. MyClass.myField gets initialized to 4
b. The constructor of System.Object gets called
c. MyClass.myField is assigned the value 5 due to the code in MyClass’s constructor
3. myDerivedProperty is assigned the value 7 due to the code in MyDerivedClass’s constructor
AddendumThought, I'd the IL that gets generated for the constructor.Looking at the C# code written in the constructor, we might expect to see code somethign like below.method public hidebysig specialname rtspecialname instance void .ctor() cil managed{ // Code size 17 (0x11) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.7 IL_0002: stfld int32 ConsoleApplication5.MyDerivedClass::myDerivedProperty IL_0007: nop IL_0008: ret} // end of method MyDerivedClass::.ctor However, what we see is something like below.method public hidebysig specialname rtspecialname instance void .ctor() cil managed{ // Code size 24 (0x18) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.6 IL_0002: stfld int32 ConsoleApplication5.MyDerivedClass::myDerivedProperty IL_0007: ldarg.0 IL_0008: call instance void ConsoleApplication5.MyClass::.ctor() IL_000d: nop IL_000e: nop IL_000f: ldarg.0 IL_0010: ldc.i4.7 IL_0011: stfld int32 ConsoleApplication5.MyDerivedClass::myDerivedProperty IL_0016: nop IL_0017: ret} // end of method MyDerivedClass::.ctori.e. first the variable initializer gets executed, then the base constructor gets called and finally we have the IL corresponding to the C# code written in the class constructor
Comments
- Anonymous
August 05, 2010
Correct - Anonymous
August 06, 2010
I think Alvaro made it sure to post only the correct information in the blog