27 Jan 2009

Here is a sample code that declares a Person class then uses Simplified Initializations to set its public properties. This code also instantiates an Anonymous Type that has two properties named exactly like the two properties of the Person class.

class Person
{
    public String Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var p = new Person { Name = "Philippe", Age = 27 };
        var q = new { Name = "Johndoe", Age = 88 };

        Console.ReadLine();
    }
}

Initializations of variables p and q looks quite similar. However, under the covers, it is very different.

Let's look at the generated C# for this, using Reflector:

private static void Main(string[] args)
{
    Person <>g__initLocal0 = new Person();
    <>g__initLocal0.Name = "Philippe";
    <>g__initLocal0.Age = 0x1b;
    Person p = <>g__initLocal0;
    var q = new {
        Name = "Johndoe",
        Age = 0x58
    };
    Console.ReadLine();
}

So, what do we see there?

First, Person's constructor is invoked (I guess they mean that you d'ont have to invoke it yourself), and that the compiler uses a temporary variable to store this new Person object. Then, the properties set in the simplified initialization are set on that temporary variable, and at last our variable is assigned the reference to the object that is now ready to be used. This is clearly done for atomicity reasons, as the object will not be available while in inconsistent state.

Second, we see that for the anonymous type, it's pretty much the same as the original code. However, there is no trace of an intermediate variable used during initializations of the object's properties. Let's have a look at the code generated for that anonymous type:

[CompilerGenerated, DebuggerDisplay(@"\{ Name = {Name}, Age = {Age} }", 
    Type="<Anonymous Type>")]
internal sealed class <>f__AnonymousType0<<Name>j__TPar, <Age>j__TPar>
{
    // Fields
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <Age>j__TPar <Age>i__Field;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <Name>j__TPar <Name>i__Field;

    // Methods
    [DebuggerHidden]
    public <>f__AnonymousType0(<Name>j__TPar Name, <Age>j__TPar Age);
    [DebuggerHidden]
    public override bool Equals(object value);
    [DebuggerHidden]
    public override int GetHashCode();
    [DebuggerHidden]
    public override string ToString();

    // Properties
    public <Age>j__TPar Age { get; }
    public <Name>j__TPar Name { get; }
}

Now, two things to note:

  1. There is no default constructor for that anonymous type, there is only a constructor that takes the values of the two properties.
  2. The two properties are declared as readonly, so they cannot be assigned once the object has be instantiated. In fact, Anonymous Types are immutable.

So, it is quite clear from the generated code that when instantiating an anonymous type, the compiler translates this into a call to the anonymous type's constructor. It is not shown in Reflector's C# disassembler, but it can be seen using Reflector's IL disassembler:

L_001e: ldstr "Johndoe"
L_0023: ldc.i4.s 0x58
L_0025: newobj instance void <>f__AnonymousType0`2<string, int32>::.ctor(!0, !1)

As expected, the call will be to the constructor of the anonymous type.

To sum it up, even if the following two lines look very similar, the reverse call will be very different:

var p = new Person { Name = "Philippe", Age = 27 };
var q = new { Name = "Johndoe", Age = 88 };

For variable p, the specified constructor will be called (in this case, the default one), then properties will be set on the newly created object. For variable q, the generated constructor will be called using properties given as parameters.



blog comments powered by Disqus