2011-05-18 53 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 
}