14

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Aparin
  • 4,393
  • 5
  • 25
  • 51
  • 6
    Your guess is correct. arg0 is `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](https://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.newobj(v=vs.110).aspx), which is used to allocate and then initialize the object via the constructor. – Mike Zboray Feb 08 '17 at 08:22
  • @mikez, Excellent link! It is what I need – Alex Aparin Feb 08 '17 at 08:31

3 Answers3

10

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)

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • I hope by "initializers" you refer to the fields being intialized before any ctor-call. In contrast to this *object-initializers* run *after* the constructor as far as I know. – MakePeaceGreatAgain Feb 08 '17 at 08:25
  • @HimBromBeere - I'd hoped it was clear from the first para that I was referring to `field initializers` which is a well-defined term in C#. I've slightly modified the second para to make it clear I'm still referring to field initializers. – Damien_The_Unbeliever Feb 08 '17 at 08:40
  • Another interesting thought that why initializations was put before calling invoking base class constructor. Maybe because of possible invoking virtual methods from base class constructor (which can actually work with data of derived class) – Alex Aparin Feb 08 '17 at 08:42
  • 1
    @LmTinyToon - I think you have to pick *some* order between field initializers, base-class constructor and instance constructor. And since instance constructor and base-class constructor are both described at the same "place", it's less thinking that those two are more closely tied together. (For the scenario where your instance constructor is `Foo() : base(something)`) – Damien_The_Unbeliever Feb 08 '17 at 08:51
3

Although the object is not 'created' in the strictest sense before the constructor call, there must be some memory allocated for it. I don't know the details, but I would guess that all instance methods of a class have an implicit first parameter, which is this; this would also be true for the constructor, as it needs to reference the object instance like any other instance method.

Codor
  • 17,447
  • 9
  • 29
  • 56
  • A better way to put it is that the object is not *done* being created. All the base class constructors have already been run, all the memory required by the object is already allocated (including any derived classes, for which the constructor didn't even run yet). This is one of the reasons that constructors should do as little work as possible - the object is half-constructed, and leaking it in any way can give you huge headaches (what happens when you call a virtual method on an object that didn't have its constructor execute yet? Fun :P). – Luaan Feb 08 '17 at 10:47
3

http://www.philosophicalgeek.com/2014/09/29/digging-into-net-object-allocation-fundamentals/

According to the above article, the CLR allocates memory first before calling into the constructor, the same way object construction happens in C++.

Dai
  • 141,631
  • 28
  • 261
  • 374