在使用.NET 3.5构建的项目中,我使用LINQ表达式在运行时动态生成代码。 LINQ表达式使用Compile方法编译并存储,以便以后用作具有LINQ to对象的谓词。
表达式有时非常复杂,难以调试。
下面是通过Visual Studio中的调试器可视化工具查看的表达式示例。
{请求 => (调用(workEnvelopeHead => (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses +<> c_ DisplayClass58).pipeline), request.WorkEnvelope.Head) 和Invoke(body => 调用(值(Wombl.Scenarios.CannedResponses + LT;&以及c _DisplayClass78).isMatch, body.SingleOrDefault()),转换(request.WorkEnvelope.Body.Any)))}
我希望能够优化上面的表达式,以便value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline
表达式替换为变量值的常量。
在这种特殊情况下,value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline
是lambda中对父作用域中变量的引用。类似的东西:
var pipeline = "[My variable's value here]";
// My lambda expression here, which references pipeline
// Func<RequestType, bool> predicate = request => ........ workEnvelopeHead.Method == pipeline ..........
原始表达式,优化应该看起来像:
{request =&gt; (调用(workEnvelopeHead =&gt; (workEnvelopeHead.Method =“[我的变量值在这里]”, request.WorkEnvelope.Head)和Invoke(body =&gt;&gt; Invoke(value(Wombl.Scenarios.CannedResponses +&lt;&gt; c__DisplayClass78).isMatch, body.SingleOrDefault()),转换(request.WorkEnvelope.Body.Any)))}
如何在编译之前在运行时对LINQ表达式进行此类优化?
答案 0 :(得分:1)
所以我继续编写了一个表达式访问者,用实际值替换变量引用。毕竟不是那么难。
用法:
var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression);
班级:
它继承自Expression this page上的代码示例中的ExpressionVisitor,因为在.NET 3.0中它是内部的。在.NET 4.0中,该类是公共的,但可能需要对此类进行一些更改。
public sealed class ExpressionOptimizer : ExpressionVisitor
{
private ExpressionOptimizer()
{
}
#region Methods
public static Expression<TDelegate> Simplify<TDelegate>(Expression<TDelegate> expression)
{
return expression == null
? null
: (Expression<TDelegate>) new ExpressionOptimizer().Visit(expression);
}
private static bool IsPrimitive(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type == typeof (string)
|| type == typeof (DateTime)
|| type == typeof (TimeSpan)
|| type == typeof (DateTimeOffset)
|| type == typeof (Decimal)
|| typeof(Delegate).IsAssignableFrom(type);
}
protected override Expression VisitMemberAccess(MemberExpression memberExpression)
{
var constantExpression = memberExpression.Expression as ConstantExpression;
if (constantExpression == null || !IsPrimitive(memberExpression.Type))
return base.VisitMemberAccess(memberExpression);
// Replace the MemberExpression with a ConstantExpression
var constantValue = constantExpression.Value;
var propertyInfo = memberExpression.Member as PropertyInfo;
var value = propertyInfo == null
? ((FieldInfo) memberExpression.Member).GetValue(constantValue)
: propertyInfo.GetValue(constantValue, null);
return Expression.Constant(value);
}
#endregion
}