Expression Trees in C# 3.0
Posted by: Granville Barnett,
on 24 Apr 2007 |
View original | Bookmarked: 0 time(s)
Out of everything in C# 3.0 this is the feature that intreges me the most - from what I have looked at this feature seems immensly powerful, LINQ to SQL takes an expression tree and uses that to generate the appropriate SQL code.
The thing I really like about expression trees is the ability to dig into them as an in-memory data structure.
In the code shown I extract parameters (types, names), expression types, and expressions.
Take a look at the below code and inspect it, run it etc...
using
System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.ObjectModel;
namespace ExpressionTrees
{
public class Program
{
public static void Main()
{
Expression<Func<int, int, int>> square = (x, y) => x * y; // in mem tree represenation of func
ReadOnlyCollection<ParameterExpression> args = square.Parameters;
Console.WriteLine("Expression: {0}", square.Body); // expr of function
foreach (ParameterExpression param in args)
{
Console.WriteLine("Param Name: {0} Type: {1}", param.Name, param.Type); // print out each arg and type
}
Func<int, int, int> squareCompiled = square.Compile(); // com
Console.WriteLine(squareCompiled(4, 4));
// constructing the square function using a binary expr
BinaryExpression be = BinaryExpression.MakeBinary(ExpressionType.Multiply,
Expression.Parameter(typeof(int), "x"), Expression.Parameter(typeof(int), "y"));
Console.WriteLine(be.NodeType); // expr type
Console.WriteLine("Param Name: {0} Type: {1}", be.Left, be.Left.Type);
Console.WriteLine("Param Name: {0} Type: {1}", be.Right, be.Right.Type);
}
}
}
C# compiler generated code:
public class Program
{
// Methods
public static void Main()
{
ParameterExpression CS$0$0000;
ParameterExpression CS$0$0001;
Expression<Func<int, int, int>> square = Expression.Lambda<Func<int, int, int>>
(Expression.Multiply(CS$0$0000 = Expression.Parameter(typeof(int), "x"),
CS$0$0001 = Expression.Parameter(typeof(int), "y")), new ParameterExpression[]
{ CS$0$0000, CS$0$0001 });
ReadOnlyCollection<ParameterExpression> args = square.Parameters;
Console.WriteLine("Expression: {0}", square.Body);
foreach (ParameterExpression param in args)
{
Console.WriteLine("Param Name: {0} Type: {1}", param.Name, param.Type);
}
Console.WriteLine(square.Compile()(4, 4));
BinaryExpression be = Expression.MakeBinary(ExpressionType.Multiply,
Expression.Parameter(typeof(int), "x"), Expression.Parameter(typeof(int), "y"));
Console.WriteLine(be.NodeType);
Console.WriteLine("Param Name: {0} Type: {1}", be.Left, be.Left.Type);
Console.WriteLine("Param Name: {0} Type: {1}", be.Right, be.Right.Type);
}
}
MSIL (only local variables):
.locals init (
[0] class [System.Core]System.Linq.Expressions.Expression'1<class
[System.Core]System.Linq.Func'3<int32, int32, int32>> square,
[1] class [mscorlib]System.Collections.ObjectModel.ReadOnlyCollection'1<class
[System.Core]System.Linq.Expressions.ParameterExpression> args,
[2] class [System.Core]System.Linq.Expressions.ParameterExpression param,
[3] class [System.Core]System.Linq.Func'3<int32, int32, int32> squareCompiled,
[4] class [System.Core]System.Linq.Expressions.BinaryExpression be,
[5] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
[6] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0001,
[7] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0002,
[8] class [mscorlib]System.Collections.Generic.IEnumerator'1<class
[System.Core]System.Linq.Expressions.ParameterExpression> CS$5$0003,
[9] bool CS$4$0004)
Enjoy.