I have simple program like this:
public class Foo
{
public Foo()
{
}
public int MyInt { get; set; } = 10;
public List<int> MyList { get; set; } = new List<int>();
}
public class Program
{
static public void Main()
{
Console.WriteLine(new Foo().MyInt);
Console.ReadLine();
}
}
I decided to see il code of such program (I am interested in Foo's constructor). Here is it:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 26 (0x1a)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.s 10
IL_0003: stfld int32 Foo::'<MyInt>k__BackingField'
IL_0008: ldarg.0
IL_0009: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_000e: stfld class [mscorlib]System.Collections.Generic.List`1<int32> Foo::'<MyList>k__BackingField'
IL_0013: ldarg.0
IL_0014: call instance void [mscorlib]System.Object::.ctor()
IL_0019: ret
} // end of method Foo::.ctor
I wondered, when I saw second line - ldarg.0. What does it mean? this pointer? but object was not created yet. How can I modify its members? My assumption is that before calling constructor, clr firstly allocates memory for object. Then initializes members to default values, then invokes constructor. Another interesting moment that object calling is last. I thought that it will be first.
this. Note that this is the case for all instance methods, the constructor is not special in this sense. The exact process is described in the newobj opcode docs, which is used to allocate and then initialize the object via the constructor. – mike z 1 hour ago