onsdag 12 mars 2008

Using an anonymous type outside its scope

With C# 3.0, Microsoft introduced "Anonymous Types" which gives us the ability to create new types in runtime.

Example:
var x = new {Name = "Fredrik", Country = "Sweden"};
x.Name = "New Name";


As you can see, object X is assigned to a new type where the properties are created in runtime. Each property type is interpreted by the assigned value which means that we still have type safety.

The anonymous type is however only available in the current scope, ie in the current method, if-statement etc. This is fine, as we normally do not want to expose the type to external code as this code does not know anything about the new type or its properties.

There are however occasions where we might need the anonymous type outside the scope. Lets say within an ASP.NET Page where you bind a control (eg. Repeater) to a list of anonymous types. Example:

IEnumerable orders = GetOrders(); //get list of orders
IEnumerable orderLines = GetOrderLines(); //get another list of order lines

//create new list based on orders and orderLines
var list = from order in orders
join orderLine in orderLines on o.OrderId equals orderLine.OrderId
select new {Customer = o.CustomerName, LineAmount = orderLine.Amount};

//create a delegate method to handle the ItemDataBound event
this.repeaterOrders.ItemDataBound += new RepeaterItemEventHandler(repeaterOrders_ItemDataBound);

//bind the repeater
this.repeaterOrders.DataSource = list;
this.repeaterOrders.DataBind();


Now, in the method for "ItemDataBound" we want to cast the DataItem to the Anonymous type to be able to use it for the Repeater output.
We can do this be creating a new generic method that casts the object to the anonymous type.


private T Cast<t>(object o, T type)
{ return ( T )o; }


Using this in the code, looks like the following:


protected void repeaterOrders_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item e.Item.ItemType == ListItemType.AlternatingItem)
{

//cast the "DataItem" property into the anonymous type
var x = Cast(e.Item.DataItem, new {Customer="", LineAmount=0});

//use the x object with ites properties based on the anonymous type
totalAmount+= x.LineAmount;

}
}


As you can see, the "client" using the Cast method must know the internal structure of the anonymous type. This is not a very nice solution when passing data between different layers, but when used in the same ASP.NET page or class I feel that it is a quite nice solution to solve the problem. And in the end...that's what really matters.

Inga kommentarer: