I recently asked a question on MSDN's LINQ to Entities forum:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/ddd2ddb4-ad77-415c-b9a3-781f759b0316
Here's the basics:
I would like to do the following transformation using an expression rewriter:
Func<string, bool> lengthFunc = s => s.Length > 5;
Func<string, bool> startFunc = s => s.StartsWith("a");
Func<string, bool> combinedFunc = s => ((s.Length > 5) && s.StartsWith("a"));
I began by making the variables lambda expressions and then combining their bodies in an AndAlso expression:
Expression<Func<string, bool>> lengthFunc = s => s.Length > 5;
Expression<Func<string, bool>> startFunc = s => s.StartsWith("a");
BinaryExpression combinedBody = Expression.AndAlso(lengthFunc.Body, startFunc.Body);
Expression<Func<string, bool>> combined = Expression.Lambda<Func<string, bool>>(combinedBody, lengthFunc.Parameters);
combined.ToString() returns: s => ((s.Length > 5) AndAlso s.StartsWith("a"))
This looks correct, but renaming the parameters in the input expressions shows the error in my approach:
Expression<Func<string, bool>> lengthExpr = sA => sA.Length > 5;
Expression<Func<string, bool>> startExpr = sB => sB.StartsWith("a");
BinaryExpression combinedBody = Expression.AndAlso(lengthExpr.Body, startExpr.Body);
Expression<Func<string, bool>> combined = Expression.Lambda<Func<string, bool>>(combinedBody, lengthExpr.Parameters);
combined.ToString() returns: sA => ((sA.Length > 5) AndAlso
sB.StartsWith("a"))
I have an unsatisfied parameter requirement,
sB, in the expression.
To get an expression body that references a single parameter, I would need to replace all uses of sB in startExpr with the ParameterExpression sA from lengthExpr.
Being that expressions are immutable, I can't simply crawl startExpr replacing all instances of sB with sA. I'll need to create a copy of startExpr with the parameter references swapped.