Immutable is, the new Anonymous Type


Overview


In the spirit of keeping my first post short and simple, i plan to write about changes to Anonymous tyes that will be of interest to quite a few developers. Anonymous types are immutable, yes its true. Now depending on your current project, prevaling point of view or things you would have read this might seem to be a good or bad thing for you. I will try and throw some light on why this is done and what the change is. Before we begin, In a quick seach on live i found many posts on Anonymous types and If you want to know, what Anonymous types are ? or how to use them ? I would recommend WesDyer’s blog.


Since anonymous type’s equality and hashcode sematics are defined by its structure ( name, type and order of members) making them immutable has interesting benefits of making the hashcode perform like a well behaved .Net type. That is the hashcode of the object does not change over its lifetime. And since the equality operator can be written to use hashcode, it benefits too, while still maintaining equality based on the structure of the Anonymous Type.


In order to understand this better let’s have a look at the GetHashCode Function, which compute the hash by doing the below computation for every member 


hash += hash * change + (field == null ? 0 : EqualityComparer<T>.Default.GetHashCode(fieldMember))


Therefore by ensuring that the members do not change, we ensure that the hash is constant for the lifetime of the object.This allows anonymous types to be used with collections like hashtables, without actually loosing them when the members are modified. There are a lot of benefits of immutabilty in that, it drastically simplifies the code that uses the object since they can only be assigned values when created and then just used (think threading). It also scopes out the feature for the primary purpose that it is designed, the definition of composite keys in Queries where equality based on structure and selecting projections from the results of a Query.


eg of join between 2 composite keys that have a common structure


from p in products  // A composite key equality


join  sl in shoppingList on new {p.Name, p.Category} equals new {sl.ItemName, sl.Cat}


select p;


or creating projections from the results sequence. 


from p in products


where p.UnitPrice >= 100


select new { Name = p.Name, Price = p.UnitPrice }; //or creating projections from the results sequence.


The Bottom line: So what’s the result of these changes on the structure of Anonymous types



  1. The Constructor will takes arguments to initialize the fields backing the public properties on the anonymous type 

  2. The default Constructor will be removed.

  3. The public properties will only have getters and no setters

  4. The name of the parameters for the constructor will be the same as the public propertes.

  5. Anonymous type construction will no longer be realized as an Object initalizer (since the anonymous type is created in a single call), but as a single constructor call.

  6. The fields are readonly.

Anonymous types construction can generate IL to be executed or an Expression Tree which can then be translated.


IL Changes


Each Anonymous Type now has a constructor that accepts the values assigned to each member on the type as arguments. The Parameter (name & type) will match the Property (name & type) on the type. As an example, consider
var v = new { A = 5, b = “bar” };


will result in constructor like public AnonymousType(TypeParameter1 A, TypeParameter2 b);  // notice the param A matches property A
and properties like 
    public TypeParameter1 A { get; }  //property A is readonly
    public TypeParameter2 b { get; }


and used as 
var v = new AnonymousType<int, string>(5, “bar”);


Further 2 instantiations of a anonymous-type using the same name & types in the same order, will automatically map to the same generic type. Though this is nothing new and has little to do with immutability I thought I mention it for completeness.


var v = new { A = 5, b = “bar” }; var v1 = new { A = 10, b = “Sree” };


will result in 
    var v = new AnonymousType<int, string>(5, “bar”);
    var v1 = new AnonymousType<int, string>(10, “Sree”);


Expression Tree


There are 2 new overloads for the “New” method added to Expression tree API that support representing anonymous types. They are …


public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)


public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo[] members)


they create and return the NewExpression object which is used to represent this Anonymous type construction as data (the changes to NewExpression class are shown below). The NewExpression class now has a members collection, this corresponds to the list of members that the arguments should be asigned to, below are some of the changes to the NewExpression class.


public sealed class NewExpression : Expression {


        ReadOnlyCollection<MemberInfo> members;


     public ReadOnlyCollection<MemberInfo> Members{


            get { return this.members; }


        }


}


The C# compiler also uses these overloads when it rewrites an anonymus type as an expression tree, this typically happens when creating queries for IQueryable like


string s = “Hello Anonymous types”;


var query = from c in s.AsQueryable()


           select new { ASCII = (int)c };



The Compiler passes in the property getters in the member’s collection, Dlinq uses this expression tree to do its translation and every one is happy. 


So when will this be avaiable ?


These changes to the compiler and the System.Core should be publically avaiable in Beta 2.


I would love to hear if you found this information usefull and things i could do to present this material better. (too much code, too little code.. more pictures etc). 


 

Comments (19)

  1. zproxy says:

    Nah, the post is just great 🙂

    By the way in LINQ May the initializer syntax was unable to initiate a generic type like this:

    new Foo<int> {

    bar = 0

    };

    But i guess this is or will be fixed, right?

  2. Jules says:

    The decision seems smart to me.

    Could you expand more on why you’ve only now decided to make this decision instead of earlier?

    Could you also explain any performance implications of this decision?

  3. Sree_c says:

    Yes, intializer syntax with generic types will work… though there is no type inference so

    var v = new Foo<int> { bar = 0 }; // will work

    var v1 = new Foo { bar = 1 }; // won’t work

    Sree

  4. Sree_c says:

    I think the simple reason we did not do this early is probably because we did not foresee all the issues, and there are always requests from customer to do interesting with anonymous types :).

    The Performace implication is are that

    1. Its a single call (ctor) instead of ctor and initializers.

    2. Possible limitation on the number of arguments that a constructor can take … none discovered.

  5. Visual Studio Orcas Beta 1 is available for download . Though quite similar to the March CTP in terms

  6. Herman says:

    Hello,

    I was wondering wether the immutable new

    anonymous type has a constructor with the same anonymous type as an argument.

    Like:

    var v = new { A = 5, b = "bar" };

    var v1 = new {v}

    Which should translate to:

    var v = new AnonymousType<int, string>(5,"bar");

    var v1 = new AnonymousType<int,string>(v);

    So that the anonymousType class has a constructor with the same  anonymousType  as an argument.

  7. Herman says:

    To clearyfy my last remark:

    The AnonymousType<int,string> defined

    by specifying/inferring the types and names of its parameters.

    Does this type also has a constructor with

    a single argument of type AnonymousType<int,string>

    like so

    class AnonymousType<int,string>{

     private int _a;

     private string _s;

     public AnonymousType(int a,string s){

        _a=a;

        _s=s;

     }

     public AnonymousType(   AnonymousType<int,string> source){

        _a=source._a;

        _s=source._s;

     }

     … other members …

    }

    }

  8. Sree_c says:

    There are no current plans to have copy constructor for the Anonymous Types.

    Could you explain the reasoning behind this.

    Since the Instance are immutable having a copy does not buy much.

    Creating another instance of the anonymous types which is a copy involves knowing the names/values/order of the arguments, these should be avaiable if the new instance is created in the same method as the first.

    var v = new { A = 5, b = "bar" };

    var v1 = new { A = 5, b = "bar" };

    v.Equals(v1);

    Anonymous types escape functions only as type "System.Object".

  9. @ Head says:

    Paul Vick posted that anonymous types will remain mutable in VB . Generally this looks good, I just hope

  10. fmarguerie says:

    After reading Paul Vick’s post, I’m not sure whether anonymous types will be mutable or not.

    Could clear this up, please?

    http://www.panopticoncentral.net/archive/2007/05/11/20566.aspx

  11. Ho sempre sostenuto che VB.NET fosse un linguaggio creato più per ragioni di mercato che per reali necessità

  12. Immutable anonymous types are now implemented in DB_Linq – a LINQ provider for MySql, Oracle and Postgres

  13. Overview In the last article I covered the &quot;results view&quot; for lazy evaluated collections like

  14. 你是如何创建属性的?

    如果你长期使用C#,相信你不会对属性这个东西感到陌生。一般地,属性是对私有字段的一个简单包装,就像这样: 代码1

    使用属性而不是直接公开私有字段的一个好处就是…

  15. lemontree says:

    转自:http://allenlooplee.cnblogs.com/

    缘起

    每次有新技术发布时,我们总能感受到两种截然不同的情绪:一种是恐惧和抵抗,伴随着这种情绪的还有诸如

  16. 缘起

    每次有新技术发布时,我们总能感受到两种截然不同的情绪:

    一种是恐惧和抵抗,伴随着这种情绪的还有诸如

  17. joinger says:

    每次有新技术发布时,我们总能感受到两种截然不同的情绪:

    一种是恐惧和抵抗,伴随着这种情绪的还有诸如

  18. hk_king says:

    文章出处:http://www.cnblogs.com/allenlooplee/archive/2008/06/01/1211520.html

    缘起

    每次有新技术发布时,我们总能感受到两种截然…

  19. rex says:

    Seems to me the readonly keyword should be used to mark the anonymous type immutable and leave it up to the programmer whether they wanted that or not