如何优化LINQ表达式?

4
在一个使用.NET 3.5构建的项目中,我正在使用LINQ表达式在运行时动态生成代码。这些LINQ表达式使用Compile方法进行编译,并存储为后续与LINQ to objects一起使用的谓词。
这些表达式有时非常复杂且难以调试。
以下是在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)))}
我想能够优化上述表达式,以便将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 => (Invoke(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
你谈论“优化”,但你提出的唯一问题是调试。有些可能会使调试更容易的东西可能会损害性能,反之亦然。你能澄清一下哪个目标对你来说更重要吗? - Jon Skeet
通过优化,我指的是以更简单的形式重写表达式树,这应该会提高性能并使表达式树更易于阅读。因此,虽然改善运行时性能和可读性都是目标,但表达式的可读性更为重要。在运行时,表达式被写入日志以帮助调试。 - John Mills
我正在考虑编写一个ExpressionVisitor来重写表达式树,将变量引用替换为具有变量值的常量。但是,我希望有人尝试过类似的事情,也许解决方案已经存在。 - John Mills
是的,您可能需要一个访问者。表达式树在很多方面都很好,但像这样操作它们是很麻烦的 :( - Jon Skeet
1个回答

1

于是我开始编写一个表达式访问器,将变量引用替换为实际值。毕竟这并不难。

用法:

var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression);

这个类:

它继承自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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接