2011-05-18 52 views
3

在使用.NET 3.5构建的项目上,我使用LINQ表达式在运行时动态生成代码。 LINQ表达式使用Compile方法进行编译并存储以供将来用作LINQ to对象的谓词。如何优化LINQ表达式?

这些表达式有时非常复杂且难以调试。

下面是通过Visual Studio中的调试器可视化工具查看的表达式示例。

{请求 =>(调用(workEnvelopeHead =>(workEnvelopeHead.Method =值(Wombl.Scenarios.CannedResponses + <> C_ DisplayClass58).pipeline) request.WorkEnvelope.Head) 并调用(体=> 调用(值(Wombl.Scenarios.CannedResponses + <>ç _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 .......... 

原表达,优化应当看起来像:

{请求=>(调用(workEnvelopeHead => (workEnvelopeHead.Method = “[我在这里的变量的值]” , request.WorkEnvelope.Head)and Invoke(body =>> Invoke(value(Wombl.Scenarios.CannedResponses + <> c__DisplayClass78).isMatch, body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)) )}

在编译之前,如何在运行时对LINQ表达式进行优化?

+1

你说的是“优化”,但你给出的唯一问题是*调试*。有些可能会使调试更容易的事情可能会损害性能,反之亦然。你能否澄清哪个目标对你很重要? – 2011-05-18 06:21:22

+0

通过优化,我的意思是以更简单的形式重写表达式树,它应该_should_提高性能并使表达式树更易于阅读。所以虽然改进的运行时性能和可读性都是目标,但表达式的可读性更重要。表达式在运行时写入日志以帮助调试。 – GiddyUpHorsey 2011-05-18 11:25:04

+0

我正在考虑编写一个ExpressionVisitor来重写表达式树,用一个具有变量值的常量替换变量引用。但是,我希望别人试图做类似的事情,也许解决方案已经存在。 – GiddyUpHorsey 2011-05-18 11:25:34

回答

1

所以我继续写了一个表达式访问器,用实际值替换变量引用。毕竟这并不难。

用法:

var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression); 

类:

它从ExpressionVisitor继承这些来自代码样本上this page因为在.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 
}