Wednesday, 1 May 2013

Basics - LINQ Expressions

LINQ is one of the most useful and most talked features added to .NET framework. It made our lives easier by providing a nice interface to program against list data and helps in writing readable code.

To support querying against in-memory collections, a number of extension methods were added to the interface IEnumerable. Following listing shows signatures of some of these extension methods:

public static long? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector);
public static long Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector);
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count);
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);

We have the interface IQueryable to support querying against remote collections. Any collection that doesn’t reside in the program’s memory is a remote collection. It can be a table in the database, a collection exposed through a service or anything similar. Following listing shows signature of corresponding extension methods defined in IQueryable:
public static long? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long?>> selector);
public static long Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long>> selector);
public static IQueryable<TSource> Take<TSource>(this IQueryable<TSource> source, int count);
public static IQueryable<TSource> TakeWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public static IQueryable<TSource> TakeWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);

Notice the difference in the signatures of methods. Methods of IEnumerable accept Func and predicate, whereas the corresponding methods of IQueryable accept Expression<Func> and Expression<Predicate>.

The difference between Func and Expression<Func> is, Func is a delegate type and Expression<Func> is a data structure. An Expression is represented in the form of a tree. Each node of the tree contains some information which can be inspected. An expression can be created very easily using lambda. An example is shown below:

Expression<Func<int, bool>> compareExpression = (num) => num == 5;

Expression Tree Visualizer is a nice tool to view an expression in the form of a tree while debugging the application. To use it on a computer, one just needs to copy the library into Visual Studio visualizers folder. You can find the instructions in the codeplex site of the sample.

Following screenshot shows tree form of the expression defined above:


A simplified version of the above expression tree can be the following:



As we see, each node contains an expression. In other words, each individual part of an expression is also an expression. These expression types are defined in the namespace System.Linq.Expressions. This means, we can create a lambda expression by hand. Following code snippet demonstrates it:
//Parameter expression for the parameter num
var parameterNumExpr = Expression.Parameter(typeof(int), "num");

//Constant expression for the constant value 5
var constantVal5Expr = Expression.Constant(5);

//Lambda expression that accepts a parameter and compares with a constant
var lambdaCompareExpression = Expression.Lambda<Func<int, bool>>(Expression.MakeBinary(ExpressionType.Equal, parameterNumExpr, constantVal5Expr), parameterNumExpr);

If you view the above created lambdaCompareExpression using Expression Tree Visualizer, you should be able to see the same tree structure as of the previous expression. This expression can be used to query select all 5’s from an array of integers as follows:

int[] array = {2,6,5,1,343,54,5,23,75,46,5,18,3287,328,012,2,5 };
var nums = array.AsQueryable().Where(lambdaCompare);

The collection nums will have 4 5’s after execution of the above statement. As you saw, it takes quite a bit of work to create and use expressions by hand. But it is important to understand how an expression is formed and its components as we use them almost everyday. Following are some of the scenarios where expressions are used:

  • Converting LINQ queries to database queries in LINQ to SQL, Entity Framework, NHibernate
  • Creating OData URLs in WCF Data Services and Web API
  • Fetching data from Windows Azure Table storage
  • Configuring entities and their properties in Entity Framework code first fluent API
  • Generating HTML input tags with validation attributes in ASP.NET MVC (K. Scott Allen explained this in his blog post on Why All the Lambdas?)
  • Features like automatic paging and sorting list data with model binding in ASP.NET 4.5 Web Forms

Expressions are heavily used in .NET framework to provide a friendly interface to the programmers. While writing queries against LINQ to SQL or Entity Framework we feel as if the queries fetch data from in-memory collection. But there is a lot of work done under the covers. Data is extracted from each expression in the query and a SQL query is formed based on the information gathered. This query is fired against the database to fetch data.

Happy coding!

No comments:

Post a Comment