Monday, June 1, 2009

Anonymous Types – Features of C# 3.0 (Part – 5)

In my previous blogs we have discussed the various new features of C# 3.0. These are listed below.

In this blog we will see what are Anonymous types?

Anonymous Types 

As the name suggests anonymous types are types which don’t have any concrete type. This doesn’t mean that anonymous types are not strongly typed. Anonymous types help you in creating real time objects without the hassle of creating a class and declaring an object for the same. Normally in .NET or any OOPS programming language we create object by first creating a class for the object and then instantiate an object for the class using the new keyword. With anonymous types one need not do all these, the developer can use the “new” keyword along with the “var” keyword and Object Initializer to create an anonymous object. The sample code for creating anonymous object is shown below.

var anonymousObj = new { FirstName = "Sandeep", LastName = "P.R" };

In the above code you can see I am creating an Anonymous object with two properties “FirstName” and “LastName” by making use of Object Initializer feature. One can access the properties defined in the Anonymous type using the Anonymous type’ variable name. One will get the intellisense feature as well with anonymous types. The below screenshot shows the intellisense displaying the properties defined above.

image

If you closely examine the intellisense you can see some methods. These methods are the ones available in the System.Object class of .NET. The reason why these methods are available is that anonymous types implicitly inherit from .NET’ System.Object class. Just to prove that Anonymous types implicitly inherit from System.Object I have disassembled the exe using .NET Reflecter. The screenshot pasted below proves just that.

image

As said previously one need not create class/type for instantiating an anonymous type but behind the scene the compiler does the extra work of creating the class/type and giving it a name. In the above screenshot one can see compiler generated class name highlighted in blue. The auto generated name cannot be accessed in your code and that is the reason the “var” keyword is used whenever anonymous types are instantiated. Anonymous types are reference types (class) and are not different from other user defined types. In user defined types the type is created by the user whereas in the case of anonymous type the compiler does the extra work of creating the type. The code pasted below is the compiler generated code for the anonymous type that we created in the above code.

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

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

    // Properties
    public <FirstName>j__TPar FirstName { get; }
    public <LastName>j__TPar LastName { get; }
}

In the above disassembled code, the first line says “CompilerGenerated”, this distinguishes user defined code from compiler generated code. Also notice the auto generated class is declared internal and sealed. The fields which hold the values of the properties are defined as read only.

Anonymous type’ properties are read only and they cannot be set at any given point. If you write a code to set the properties of anonymous types the following error will be thrown.

var anonymousObj = new { FirstName = "Sandeep", LastName = "P.R" };
anonymousObj.FirstName = "Sad";// Error prone code.

Compile time error which is thrown when you try to assign a value to a property of an Anonymous type is pasted below.

Property or indexer 'AnonymousType#1.FirstName' cannot be assigned to -- it is read only

Anonymous types can have only read only properties and they cannot have any method definition or events but they inherit the default methods of the Object class. If you use the Equals methods of an anonymous type the system loops through all the properties and returns true if all the properties are same. Even GetHashCode method works based on the equality of properties. So the implementation of Equals and GetHashCode changes in the case of Anonymous Types. The output of ToString and GetType methods which are inherited from the System.Object class is pasted below.

var anonymousObj = new { FirstName = "Sandeep", LastName = "P.R" };
Console.WriteLine(anonymousObj.ToString());
Console.WriteLine(anonymousObj.GetType().ToString());

//Output of ToString
{ FirstName = Sandeep, LastName = P.R }
//Output of GetType().ToString()
<>f__AnonymousType1`2[System.String,System.String]

The scope of anonymous types is limited to only method level. If one wants to transfer anonymous types from one method to another method then one has to cast the anonymous type to object and then pass it to other functions. In the function where you are receiving the anonymous object as an Object type there is no way to directly retrieve the property values. You cannot make use of the property names and retrieve the values. If you are passing anonymous types to another function then the below code is the only way to retrieve the property values.

//Method where anonymous types are declared and passed to another method.
private void MakingUseOfAnonymousTypes()
{
    var anonymousObj = new { FirstName = "Sandeep", LastName = "P.R" };
    TakesAnonymousType(anonymousObj);
}

//Method which receives anonymous object as a method a parameter in the form object.
private void TakesAnonymousType(object obj)
{  
    //Getting the object' type.
    Type anonymous = obj.GetType();
    //Retrieving all the properties of the anonymous object.
    System.Reflection.PropertyInfo [] propertyInfo  = anonymous.GetProperties();
    //Looping through all the properties to retrieve the name and value.
    foreach (System.Reflection.PropertyInfo propInfo in propertyInfo)
    {
        Console.WriteLine(propInfo.Name + ": " + propInfo.GetValue(obj, null));
    }       
}

In the above code we are creating anonymous types in the first method (MakingUseOfAnonymousTypes) and passing the anonymous type to the next method. “TakesAnonymousType” method takes the anonymous type as a System.object type argument. Inside the method we are Making use of Reflection and getting the type of the object. After that we are retrieving the property collection of the object using the GetProperties method. Then looping through each property we are retrieving the property’ name and value.

Scenarios where anonymous types can be used

Anonymous types can be used where we want to use the scaled down version of a type with one or two properties. Suppose you have class called Employees with the following structure.

public class Employee
{
    public string FirstName
    { get; set; }
    public string LastName
    { get; set; }
    public int Age
    { get; set; }
    public DateTime DOB
    { get; set; }
    public string Department
    { get; set; }
    public string Address
    { get; set; }
    //Many more properties
}

Now there can be scenario in your business logic where you want to make use of only few of these properties, say FirstName and Department, instead of the long list of properties. In such scenarios you can create a scaled down version of the Employee class with only the required properties which you are going to use. Sample code is pasted below.

//Normal object with all the properties initialized
Employee emp = new Employee { FirstName = "Sandeep", LastName = "P.R", Address = "Blah blah", Age = 29, Department = "Software", DOB = new DateTime(1981, 06, 09) };
//Anonymous type
var scaledDownEmp = new { emp.FirstName, emp.Department };

In the above example you can see we are not specifying any names to the properties of the anonymous type instead we are directly using the property names of the Employee object. In such cases the compiler will assign the same name and type to the properties as that of the object from which it is being created, in this case Employee object. The compiler will automatically designate FirstName and Department as the property names and also assign the same data type to the anonymous object properties.

The best use of Anonymous types can be exemplified in the “Select” extension method of LINQ as shown below.

//Initializing the generic list collection object with two Employee object.
System.Collections.Generic.List<Employee> list = new System.Collections.Generic.List<Employee> { new Employee { FirstName = "Sandeep", LastName = "P.R", Address = "Blah blah", Age = 29, Department = "Software", DOB = new DateTime(1981, 06, 09) }, new Employee{FirstName = "Blah", LastName = "Blah blah", Address="blah blah", Age=19}};
//Another employee object being initialized.       
Employee emp = new Employee
{
      FirstName = "Employee 1",
      LastName = "Last Name",
      Address = "Blah blah",
      Age = 29,
      Department = "Software",
      DOB = new DateTime(1981, 06, 09)
};
//Another way of adding the emplyee object to the generic list collection.
list.Add(emp);
//Using LINQ extension methods and filtering out employees who are aged above 21
var empColl = from employee in list
      where employee.Age > 21
      select new { employee.FirstName, employee.Address };
//Looping through the anonymous object collection and printing the properties.
foreach (var em in empColl)
{
      Console.WriteLine(em.FirstName, em.Address);
}

From the above sample code we can see that we are creating a Generic List collection object and adding the employee object into the collection by making use of Object Initializer feature. Then we are filtering out the employees who are above 21 years of age from the collection using the LINQ’ Extension methods where, select and from. If you note in the select statement we are creating a new anonymous type with FirstName and Address as properties. empColl will hold a collection of anonymous types having FirstName and Address as properties. Immediatly below the LINQ expression we are looping through the anonymous collection and printing the properties.

So that’ about Anonymous types. Next we will see what are Lambda expressions, till then try to know more.

Sandeep

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete

Please provide your valuable comments.