On a project built with .NET 3.5, I am using LINQ expressions to dynamically generate code at runtime. The LINQ expressions are compiled using the Compile method and stored for later use as predicates with LINQ to objects.
The expressions are sometimes quite complicated and difficult to debug.
Below is an example of an expression viewed through the debugger visualizer in Visual Studio.
{request
=> (Invoke(workEnvelopeHead
=> (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses+<>c_DisplayClass58).pipeline),
request.WorkEnvelope.Head)
And Invoke(body =>
Invoke(value(Wombl.Scenarios.CannedResponses+<>c_DisplayClass78).isMatch,
body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}
I would like to be able to optimize expressions like the above so that the value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline expression is replaced with a constant that is the variable’s value.
In this particular case, value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline is a reference in the lambda to a variable in the parent scope. Something like:
var pipeline = "[My variable's value here]";
// My lambda expression here, which references pipeline
// Func<RequestType, bool> predicate = request => ........ workEnvelopeHead.Method == pipeline ..........
The original expression, optimized ought to look like:
{request => (Invoke(workEnvelopeHead =>
(workEnvelopeHead.Method = “[My variable’s value here]”,
request.WorkEnvelope.Head) And Invoke(body => > Invoke(value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass78).isMatch,
body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}
How can I make such optimizations at runtime to the LINQ expression, before compiling?
So I went ahead and wrote an expression visitor that replaces the variable references with the actual value. It wasn’t so hard to do after all.
Usage:
The class:
It inherits from ExpressionVisitor which came from the code samples on this page because in .NET 3.0 it is internal. In .NET 4.0 the class is public but might require some changes to this class.