Friday, 28 September 2012

Expression Tree in c#


Expression trees represent code in a tree-like data structure, where each node is an expression. You can compile and run code represented by expression trees. This enables dynamic modification of executable code.

When a lambda expression is assigned to a variable of type Expression, the compiler emits code to build an expression tree that represents the lambda expression. The Expression tree can be parsed as shown below. Next come the compiling of the expression tree and then execute. Only expression trees that represent lambda expressions can be executed. Expression trees that represent lambda expressions are of type LambdaExpression or Expression. To execute these expression trees, call the Compile method to create an executable delegate, and then invoke the delegate.

     //Creating Expression Trees from Lambda Expressions
     Expression<Func<int, bool>> lambda = num => num < 5;

     //Parsing Expression Trees
      ParameterExpression param = (ParameterExpression)lambda.Parameters[0];
      BinaryExpression operation = (BinaryExpression)lambda.Body;
      ParameterExpression l = (ParameterExpression)operation.Left;
      ConstantExpression r = (ConstantExpression)operation.Right;

      Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
                        param.Name, l.Name, operation.NodeType, r.Value);
           
      // Compiling the expression tree into a delegate.
      Func<int, bool> result = lambda.Compile();

      // Invoking the delegate and writing the result to the console.
      Console.WriteLine("Result for execution - {0}",result(4));



 To create expression trees by using the API, use the Expression class. This class contains static factory methods that create expression tree nodes of specific types, for example, ParameterExpression, which represents a variable or parameter, or MethodCallExpression, which represents a method call. ParameterExpression, MethodCallExpression, and the other expression-specific types are also defined in the System.Linq.Expressions namespace. These types derive from the abstract type Expression. Now we will see how we can create the Above stated expression unsing Expression class.

//Creating Expression Trees by Using the API
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(
                    numLessThanFive,
                    new ParameterExpression[] { numParam });

Once you keep a breakpoint you see the following –



In .NET Framework 4, the expression trees API also supports assignments and control flow expressions such as loops, conditional blocks, and try-catch blocks. By using the API, you can create expression trees that are more complex than those that can be created from lambda expressions by the C# and Visual Basic compilers.


Expression trees should be immutable. This means that if you want to modify an expression tree, you must construct a new expression tree by copying the existing one and replacing nodes in it. You can use an expression tree visitor to traverse the existing expression tree.

Use Expression Trees to Build Dynamic Queries

In LINQ, expression trees are used to represent structured queries that target sources of data that implement IQueryable. For example, the LINQ to SQL provider implements the Iqueryable interface for querying relational data stores. The C# and Visual Basic compilers compile queries that target such data sources into code that builds an expression tree at runtime. The query provider can then traverse the expression tree data structure and translate it into a query language appropriate for the data source.
Expression trees are also used in LINQ to represent lambda expressions that are assigned to variables of type Expression.
The following example shows you how to use expression trees to construct a query against an IQueryable data source and then execute it. The code builds an expression tree to represent the following query:

//Creating the follwoinh C# Query :
companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)
           
// The IQueryable data to query.
IQueryable<String> queryableData = companies.AsQueryable<string>();

// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression pe = Expression.Parameter(typeof(string), "company");

// ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****

// Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Expression right = Expression.Constant("coho winery");
Expression e1 = Expression.Equal(left, right);

// Create an expression tree that represents the expression 'company.Length > 16'.
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
right = Expression.Constant(16, typeof(int));
Expression e2 = Expression.GreaterThan(left, right);

// Combine the expression trees to create an expression tree that represents the
// expression '(company.ToLower() == "coho winery" || company.Length > 16)'.
Expression predicateBody = Expression.OrElse(e1, e2);

// Create an expression tree that represents the expression
// 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
MethodCallExpression whereCallExpression = Expression.Call(
                typeof(Queryable),
                "Where",
                new Type[] { queryableData.ElementType },
                queryableData.Expression,
                Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));
// ***** End Where *****

// ***** OrderBy(company => company) *****
// Create an expression tree that represents the expression
// 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderByCallExpression = Expression.Call(
                typeof(Queryable),
                "OrderBy",
                new Type[] { queryableData.ElementType, queryableData.ElementType },
                whereCallExpression,
                Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
// ***** End OrderBy *****

// Create an executable query from the expression tree.
IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);

// Enumerate the results.
foreach (string company in results)
     Console.WriteLine(company);

No comments:

Post a Comment