Expression Tree Tutorial ForEach Expression
You can build an expression tree to perform a foreach loop by using Expression.Loop
method. For example, you have the following code.
var list = new List<int>() { 10, 20, 30 }; foreach (var loopVar in list) { Console.WriteLine(loopVar); }
Here is the code that is required to build the same functionality using expression tree.
public static Expression ForEach(Expression collection, ParameterExpression loopVar, Expression loopContent) { var elementType = loopVar.Type; var enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType); var enumeratorType = typeof(IEnumerator<>).MakeGenericType(elementType); var enumeratorVar = Expression.Variable(enumeratorType, "enumerator"); var getEnumeratorCall = Expression.Call(collection, enumerableType.GetMethod("GetEnumerator")); var enumeratorAssign = Expression.Assign(enumeratorVar, getEnumeratorCall); var moveNextCall = Expression.Call(enumeratorVar, typeof(IEnumerator).GetMethod("MoveNext")); var breakLabel = Expression.Label("LoopBreak"); var ifThenElseExpr = Expression.IfThenElse( Expression.Equal(moveNextCall, Expression.Constant(true)), Expression.Block(new[] { loopVar }, Expression.Assign(loopVar, Expression.Property(enumeratorVar, "Current")), loopContent ), Expression.Break(breakLabel) ); var loop = Expression.Loop(ifThenElseExpr, breakLabel); var block = Expression.Block(new[] { enumeratorVar }, enumeratorAssign, loop ); return block; }
This function can be easily used as shown below.
var list = new List<int>() { 10, 20, 30 }; var collection = Expression.Parameter(typeof(List<int>), "collection"); var loopVar = Expression.Parameter(typeof(int), "loopVar"); var loopBody = Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(int) }), loopVar); var loop = ForEach(collection, loopVar, loopBody); var results = Expression.Lambda<Action<List<int>>>(loop, collection).Compile(); results(list);