如何优化LINQ表达式?

时间:2011-05-18 06:10:45

标签: optimization linq-expressions

在使用.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表达式进行此类优化?

1 个答案:

答案 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
}