4

在使用 .NET 3.5 构建的项目中,我使用 LINQ 表达式在运行时动态生成代码。LINQ 表达式使用 Compile 方法编译并存储以供以后用作 LINQ to 对象的谓词。

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

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

{request => (Invoke(workEnvelopeHead => (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses+<>c_ DisplayClass58).pipeline), request.WorkEnvelope.Head) 和 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 = "[My variable's value here]", request.WorkEnvelope.Head) And Invoke(body => > Invoke(value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass78) .isMatch, body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}

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

4

1 回答 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
}
于 2011-05-18T14:52:12.237 回答