Friday, May 1, 2009

Anonymous Type Acrobatics

In C# 3.0, the idea of the anonymous type was introduced. Basically, this allows you to create a type, at compile time, that is both strongly-typed, but has no actual "name" within the code. This can be extremely useful when trying to whittle down a set of objects that you might want to bind to some kind of tabular databound control, such as a DataGridView in WinForms or GridView in ASP.NET.

If you're familiar with Linq, you're familiar with the concept, so you know that it's possible to set the DataSource of some databound controls to the result of a Linq query that produces anonymous types, but did you know that you can actually reuse a list of anonymous types generated from a Linq query in order to sort or perform some other action? Enter the System.Expressions namespace. Within the System.Expressions namespace are a series of classes that allow you to dynamically generate lambdas and methods on the fly, and it's surprisingly fast (tests show that Expressions, when used properly, run faster than reflection.)

This can be very useful in several situations. What if we don't want to fetch data from the database a second time, for performance reasons, but we still want the same columns returned back from the first Linq query that generated an IEnumerable of anonymous types? Using Expressions, we can sort this data. The following code gives a good example of how to do this. It's an extension method, and sorts the anonymous type by the property named in the sortProperty string. I've added comments where I've need to in order to explain what each Expression would look like in code. You'll notice that a series of tokens are built one after another and are built upon each other, until the entire lambda is built. At that point, we compile the lambda, and invoke it dynamically, passing in an IEnumerable. Make sure to have a "using System.Linq.Expressions;" at the top of your code file.


public static class EnumerableExtensions
{
public static IEnumerable Sort(this IEnumerable _this, string sortProperty)
{
// get the generic type argument of the enumerable.
Type t = _this.AsQueryable().GetType().GetGenericArguments()[0];

// Create a parameter that has the type of the query expression or IEnumerable
// {x}
ParameterExpression xParameter = Expression.Parameter(_this.GetType(), "x");

// Create a parameter called "person" of type "t" from above:
// {person}
ParameterExpression personParameter = Expression.Parameter(t, "person");

// Create an expression to access the member:
// {person.LastName}
MemberExpression prop = Expression.Property(personParameter, sortProperty);

// Join the parameter expression and the person in a lambda:
// {person => person.LastName}
Expression sort = Expression.Lambda(prop, personParameter);

// Call OrderBy on the result and use the lambda from above:
// {x.OrderBy(person => person.LastName)}
Expression orderByCall = Expression.Call(typeof(Enumerable), "OrderBy", sort.Type.GetGenericArguments(), xParameter, sort);

// Call .ToList on the result of that, to immediately execute the query:
// {x.OrderBy(person => person.LastName).ToList()}
Expression toListCall = Expression.Call(typeof(Enumerable), "ToList", orderByCall.Type.GetGenericArguments(), orderByCall);

// Create a new lambda expression:
// {x => x.OrderBy(person => person.LastName).ToList()}
LambdaExpression lambda = Expression.Lambda(toListCall, xParameter);

// Compile and invoke the method. Returns List<T>.
IEnumerable bindingobject = (IEnumerable)lambda.Compile().DynamicInvoke(_this);

return bindingobject;
}
}