Showing posts with label Anon Methods. Show all posts
Showing posts with label Anon Methods. Show all posts

Sunday, 22 January 2012

Anonymous Types In C# 3.0

This post is about the Anonymous types in C#, and the object initializer syntax.

It is well known that starting from C# 3.0, you can initialize an object like this.

  1. var boy = new { Name = "Jim", Age = 2 };  
You specify the properties of an object, and at compile time, the compiler will create a new (anonymous) type, with the properties you specify, and with a constructor that can take the same number of arguments.

Now, let us examine our anonymous type in detail by using reflection. We'll examine whether the type is a class, along with the type's name. If you run this,

  1. static void Main(string[] args)  
  2.         {  
  3.   
  4.             var boy = new { Name = "Jim", Age = 2 };  
  5.   
  6.             Console.WriteLine("Name=" + boy.GetType().Name);  
  7.             Console.WriteLine("BaseType=" + boy.GetType().BaseType.Name);  
  8.             Console.WriteLine("Asm=" + boy.GetType().Assembly.FullName);  
  9.             Console.WriteLine("IsClass=" + boy.GetType().IsClass);  
  10.         }  

You'll get some output like
Name=<>f__AnonymousType0`2
BaseType=Object
Asm=AnonymousTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
IsClass=True

Needless to say, the Name will be a random name, and the Assembly's name depends on your own project name. The key point is, we just established that the type is there in the assembly - which means, as I mentioned, the compiler created a type at compile time itself. You can have a look at the IL if you are interested.

Now, let us examine the observation that the anonymous type has a constructor that takes the same number of arguments as that of properties (i.e, in this case, the number of constructor arguments will be equal to the number of properties we specified in the object initializer, of types string and int). We can do that easily by creating a new instance of the anonymous type we have, using reflection. Add this to the tail end of the last piece of code.

  1. //These two calls will fail with a run time exception, Just keep them commented  
  2. //var newboy = Activator.CreateInstance(boy.GetType(), null);  
  3. //var newboy = Activator.CreateInstance(boy.GetType(), new object[] { "Joe"});  
  4.   
  5. //Only this will work. Creating a new boy  
  6. var newboy=Activator.CreateInstance(boy.GetType(),new object[]{"Joe",2});  
  7.   
  8. //Just write back the name of new boy  
  9. Console.WriteLine(newboy.GetType().GetProperty("Name").GetValue(newobj, null));  

You can see that only the last call will work, as we need to pass the same number of arguments while instantiating.

Note that you can have arrays of anonymous types as well, like this.

  1. var guys = new[]  
  2.          {  
  3.                  new {Name="Joe", Age=10},  
  4.                  new {Name="James", Age=22},  
  5.                  new {Name="Jim", Age=23},  
  6.                  new {Name="Jerard", Age=10},  
  7.          };  

Further more, I just want to mention one more point. You may not need to assign the property explicitly, when you use the object initializer syntax. Consider this code.

  1. var guy1 = new { Name = "Ken", Age = 30 };  
  2. var guy2 = new { guy1.Name, Age = 30 };  
  3.   
  4. Console.WriteLine(guy1.GetType().Name + " - " + guy1.Name);  
  5. Console.WriteLine(guy2.GetType().Name + " - " + guy2.Name);  


The key point to note here is, for guy 2, we are not explicitly specifying the Name property. Instead, we are just specifying that the name of Guy2 is same as Guy1. The compiler will assume the property name from the given parameter's name (in fact, the last part of the specified parameter, in this case 'Name') - This is called Projection. Obviously, you'll find that both guy1 and guy2 are of the same type as well.

Can you guess the output of this code as well?

  1. string Name = "Guy2";  
  2.   
  3. var guy1 = new { Name = "Ken", Age = 30 };  
  4. var guy2 = new { Name, Age = 30 };  
  5.   
  6. Console.WriteLine(guy1.GetType().Name + " - " + guy1.Name);  
  7. Console.WriteLine(guy2.GetType().Name + " - " + guy2.Name);  


Why anonymous types are interesting? Because we use them in various ways, especially while using LINQ syntax. Here is a basic example


  1. var oldGuys = from guy in guys  
  2.                           where guy.Age > 20  
  3.                           select new { guy.Name };  

Revisiting Few C# Concepts - Delegates, Anon Methods, Lambdas, Expression Trees

Let us explore few concepts about Delegates, Anonymous methods, Lambdas and Expression Trees. This is an introductory post, and I’ll follow up with more posts. These code examples are pretty simple, you can fire up a C# Console application in Visual Studio and try these examples if you are interested.

Delegates

We know that a delegate is a type that can reference a method. For example, consider this example to define a delegate and create a delegate instance.

  1. //Example 1 - Creating a delegate instance using Named method  
  2.   
  3. public delegate int BinaryOperationDelegate(int x,int y);  
  4.   
  5.  class Program  
  6.  {  
  7.      static void Main(string[] args)  
  8.      {  
  9.          //Create a delegate instance using named method  
  10.          var add = new BinaryOperationDelegate(AddOperation);  
  11.          int result = add(20, 30);  
  12.          Console.WriteLine(result);  
  13.      }  
  14.   
  15.      static int AddOperation(int x,int y)  
  16.      {  
  17.          return x+y;  
  18.      }  
  19.  }  
The above code will give you an output of 50, no doubt, right ? :)

Anonymous Methods

Now, you may know that with C# 2.0, we can use anonymous methods to create a delegate instance with out a named method. Let us re-write the above implementation leveraging an anon method. Instead of the method name, you’ve to use the ‘delegate’ keyword. Also, note that there is no need to specify a return type – because the return type will be inferred from the delegate signature.
  1. //Example 2 - Creating a delegate instance using Anon method  
  2.   
  3. public delegate int BinaryOperationDelegate(int x,int y);  
  4.   
  5.  class Program  
  6.  {  
  7.      static void Main(string[] args)  
  8.      {  
  9.          //Create a delegate instance using anon method  
  10.          BinaryOperationDelegate add=   
  11.                  delegate(int a, int b) { return a+b;} ;   
  12.          int result = add(20, 30);  
  13.          Console.WriteLine(result);  
  14.      }  
  15.   
  16.  }  

Lambdas

And of course, you might also know that with C# 3.0, you can use Lambdas for producing anonymous methods. A lamda expression is exactly a function, that can contain statements and expressions. Here is the equivalent of above code, still shortened using a lambda

  1.    
  2. //Example 3 - Creating a delegate instance using statement lambda  
  3.   
  4.  public delegate int BinaryOperationDelegate(int x, int y);  
  5.  class Program  
  6.  {  
  7.      static void Main(string[] args)  
  8.      {  
  9.          //Create a delegate instance using a statement lambda  
  10.          BinaryOperationDelegate add =(a,b)=>{  
  11.                                              //this statement block can contain   
  12.                                              //multiple statements    
  13.                                              return a+b;   
  14.                                              };  
  15.   
  16.          int result = add(20, 30);  
  17.          Console.WriteLine(result);  
  18.      }  
  19.   
  20.   
  21.  }      

In the above example, note the lambda syntax that replaces the anon method syntax in example 2
  1. (a,b)=>{  
  2.             return a+b;   
  3.        };  
The types of input parameters a and b and the return type will be inferred correctly by the compiler, based on the context. How ever, on scenarios where the compiler can't infer the type directly, you can provide that explicitly. Like this.
    BinaryOperationDelegate add =(int a, int b)=>{ return a+b; };

There are basically two type of lambdas - Statement Lamdas and Expression Lambdas. The above example shows a statement lambda, as the right hand expression is inside a statement block, of the form
(param1, param2)=> { statement1; statement2; } ;

If you won't have input parameters, you may use the syntax
()=> { statement1; statement2; } ;

=> simply means 'goes to', and you may say that the input parameters goes to the statements (for some processing) :)

Statement Lambdas And Expression Lambdas


We’ve seen how to create Statement lambdas in the above example. Now, let us explore a bit about Expression Lambdas (or single line lambdas). The syntax is similar to statement lambdas, but for expression lambdas, the right hand expression should not be inside a statement block  { }. Instead of having statements on the right side, an Expression Lambda can have a single line expression on the right hand side. Here is the simple example, with out the statement block.

  1. public delegate int BinaryOperationDelegate(int x, int y);  
  2.   
  3. class Program  
  4. {  
  5.     static void Main(string[] args)  
  6.     {  
  7.         //Expression Lambda  
  8.         BinaryOperationDelegate add =(a, b)=>a+b;  
  9.         int result = add(20, 30);  
  10.   
  11.         Console.WriteLine(result);  
  12.     }  
  13. }  
The above code produces the same result as in the case of stament lambdas. How ever, Expression lamdba has an advantage over statement lambda. When an expression lambda is assigned to a variable of type Expression, the compiler emits code to build an expression tree that represents the lambda expression, instead of a delegate instance.

  1. //Example 4 - Expression Lambdas  
  2.   
  3.  public delegate int BinaryOperationDelegate(int x, int y);  
  4.   
  5.  class Program  
  6.  {  
  7.      static void Main(string[] args)  
  8.      {  
  9.          //Expression Lambda to delegate instance  
  10.          BinaryOperationDelegate add =(a, b)=>a+b;  
  11.          int result1 = add(20, 30);  
  12.   
  13.          //Expression Lambda to Expression tree  
  14.          Expression<BinaryOperationDelegate> addExpr = (a, b) => a + b;  
  15.   
  16.          //Let us compile the expression tree before executing the same  
  17.          var compiledAdd = addExpr.Compile();  
  18.          int result2=compiledAdd(20,30);  
  19.            
  20.   
  21.          Console.WriteLine(result1);  
  22.          Console.WriteLine(result2);  
  23.      }  
  24.  }  

In the above example, you saw that we are assigning our expression lambda to the System.Linq.Expression<TDelegate> to create an expression tree, and the compiling it to get the actual delegate. Expression trees provide us a powerful way to represent code/logic as data, that can be modified and/or interpreted at runtime if required.

Example Usages for Lambdas

These are some of the areas you may find using Lambdas pretty often.
To provide inline event handlers like

  1.  button.Click += (sender,args) =>  
  2. {  
  3. };  
To find items in a collection

  1. var dogs= animals.Where(animal => animal.Type == "dog");  
For iterating a collection, like

  1. animals.ForEach(animal=>Console.WriteLine(animal.Name));  
Creating a custom object

  1. var myObj= mySource.Select(x => new {Name = x.name, Age= x.age});  
Simple one line methods

  1. Func<intint> add = x => x + x;  
For aggregate operations

  1. double charCount = document.Sum(word => word.Length)