Freigeben über


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