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 the CIL 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 the second line, ldarg.0
, what does it mean? this
pointer? But the object was not created yet. How can I modify its members? My assumption is that before calling constructor, clr
first allocates memory for the object. Then initializes members to default values, and then invokes the constructor. Another interesting moment that the object calling is last. I thought that it would be first.
Field initializers are a C# feature, not a CLR one. When you write a field initializer, the C# compiler has to put the code to implement that somewhere, and where it puts it is inside the body of any constructors.
And since these initializers are run "before" the constructor, that's why the actual base-class constructor is run later.
(And so, yes, the first parameter is as you inferred, this
)