다음을 통해 공유


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

  • Anonymous
    April 13, 2007
    The comment has been removed

  • Anonymous
    April 15, 2007
    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?

  • Anonymous
    April 17, 2007
    The comment has been removed

  • Anonymous
    April 17, 2007
    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.
  • Anonymous
    April 21, 2007
    Visual Studio Orcas Beta 1 is available for download . Though quite similar to the March CTP in terms

  • Anonymous
    April 23, 2007
    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.

  • Anonymous
    April 23, 2007
    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 ... } }

  • Anonymous
    April 24, 2007
    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".

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

  • Anonymous
    May 12, 2007
    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

  • Anonymous
    May 14, 2007
    Ho sempre sostenuto che VB.NET fosse un linguaggio creato più per ragioni di mercato che per reali necessità

  • Anonymous
    September 12, 2007
    Immutable anonymous types are now implemented in DB_Linq - a LINQ provider for MySql, Oracle and Postgres

  • Anonymous
    November 29, 2007
    Overview In the last article I covered the &quot;results view&quot; for lazy evaluated collections like

  • Anonymous
    June 05, 2008
    你是如何创建属性的? 如果你长期使用C#,相信你不会对属性这个东西感到陌生。一般地,属性是对私有字段的一个简单包装,就像这样: 代码1 使用属性而不是直接公开私有字段的一个好处就是...

  • Anonymous
    June 06, 2008
    转自:http://allenlooplee.cnblogs.com/ 缘起 每次有新技术发布时,我们总能感受到两种截然不同的情绪:一种是恐惧和抵抗,伴随着这种情绪的还有诸如

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

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

  • Anonymous
    March 27, 2009
    文章出处:http://www.cnblogs.com/allenlooplee/archive/2008/06/01/1211520.html 缘起 每次有新技术发布时,我们总能感受到两种截然...

  • Anonymous
    February 04, 2016
    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