Tuesday, July 03, 2007

Anonymous Type in C#

          Anonymous types are a convenient language feature of C# and VB that enable developers to concisely define inline CLR types within code, without having to explicitly define a formal class declaration of the type.
           Anonymous types are particularly useful when querying and transforming/projecting/shaping data with LINQ.

            C# "Orcas" introduces a new var keyword that may be used in place of the type name when performing local variable declarations. 

             A common misperception that people often have when first seeing the new var keyword is to think that it is a late-bound or un-typed variable reference (for example: a reference of type Object or a late-bound object like in JavaScript).  This is incorrect -- the var keyword always generates a strongly typed variable reference.  Rather than require the developer to explicitly define the variable type, though, the var keyword instead tells the compiler to infer the type of the variable from the expression used to initialize the variable when it is first declared.

            The var keyword can be used to reference any type in C# (meaning it can be used with both anonymous types and explicitly declared types).  In fact, the easiest way to understand the var keyword is to look at a few examples of it using common explicit types.  For example, I could use the var keyword like below to declare three variables:

var a = 5;
var b = "5"
var c = 5.555;
var d = new Class();
var e = a;

int f = 6;
string g = "6"
double h = 6.666;

Fig - (1) Use of anonymous variable in code.

              You can look in to the IL code and found that IL is treating anonymous variables same as normal variable depending on their initialization. You can see the IL code below,

.method private hidebysig instance void UseOfAnonymousTypes() cil managed
{
// Code size 50 (0x32)
.maxstack 1
.locals init ([0] int32 a,
[1] string b,
[2] float64 c,
[3] class LearnLINQ.SimpleExamples d,
[4] int32 e,
[5] int32 f,
[6] string g,
[7] float64 h)
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: stloc.0
IL_0003: ldstr "5"
IL_0008: stloc.1
IL_0009: ldc.r8 5.5549999999999997
IL_0012: stloc.2
IL_0013: newobj instance void LearnLINQ.SimpleExamples::.ctor()
IL_0018: stloc.3
IL_0019: ldloc.0
IL_001a: stloc.s e
IL_001c: ldc.i4.6
IL_001d: stloc.s f
IL_001f: ldstr "6"
IL_0024: stloc.s g
IL_0026: ldc.r8 6.6660000000000004
IL_002f: stloc.s h
IL_0031: ret
} // end of method Class1::UseOfAnonymousTypes

 Fig - (2) IL generated for Anonymous Type

          As you can see that we have assigned 5 to "a". IL treats "a" as int32. Same is the case for remaining all. From this you can say that IL detects type of anonymous variable from their initialization. So you can declare anonymous variable without initializing it. Second rule for anonymous type is that you can not use Anonymous variable as a member of class, sturct or interface. So below line will not complile.

class LearnAnonymousType
{
       // Below line will give error
       var a = 5;
}

Fig - (3) Defining Anonymous variable as member field in class

    Third rule is that you can not pass or used for Anonymous type as a method argument. See below,

class LearnAnonymousType
{
       // Below line will give error
       function void sum(var Argument)
      {
      }
}

Fig - (4) Passing anonymous type as argument to function

     Fourth rule is, anonymous type can not be static.

      I hope this article has helped you in understanding the concept. Now lets have a simple quiz.

Quiz

Which of the following code fragments compile and which don't (and why)? Have fun!

Fragment 1

using System;
class Lti
{
   public static void Main()
   {
      var a;
      a = 123;
   }
}

Fragment 2

using System;
class Lti
{
   public static void Main()
   {
          int a = 123;
          var b = a;
   }
}

Fragment 3

using System;
using System.Collections.Generic;
class Lti
{
   public static void Main()
   {
              IEnumerable<string> l = new List<string>();
              var m = l;
              int i = m.Count;
   }
}

Fragment 4

using System;
using System.Collections.Generic;
class Lti
{
   private var a = 123;
   private const var b = 123;
   private static var c = 123;
   public static void Main()
   {
   }
}

1 comment:

Gabe said...

Raja, Thanks for the post, i found the info i was looking for.

I have been trying to declare a reference to a list of an aononymous type. I don't think you can based on the rules you listed.

also i think this is a typo:
So you can declare anonymous variable without initializing it.


Later,

Gabe