如何优化LINQ表达式?

发布于 2024-11-08 03:13:19 字数 1434 浏览 0 评论 0原文

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

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

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

{请求 => (调用(workEnvelopeHead => (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses+<>c_DisplayClass58).pipeline), 请求.WorkEnvelope.Head) 并调用(body => 调用(值(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 ..........

优化后的原始表达式应该如下所示:

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

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

On a project built with .NET 3.5, I am using LINQ expressions to dynamically generate code at runtime. The LINQ expressions are compiled using the Compile method and stored for later use as predicates with LINQ to objects.

The expressions are sometimes quite complicated and difficult to debug.

Below is an example of an expression viewed through the debugger visualizer in 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)))}

I would like to be able to optimize expressions like the above so that the value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline expression is replaced with a constant that is the variable's value.

In this particular case, value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline is a reference in the lambda to a variable in the parent scope. Something like:

var pipeline = "[My variable's value here]";
// My lambda expression here, which references pipeline
// Func<RequestType, bool> predicate = request => ........ workEnvelopeHead.Method == pipeline ..........

The original expression, optimized ought to look like:

{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)))}

How can I make such optimizations at runtime to the LINQ expression, before compiling?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

捶死心动 2024-11-15 03:13:19

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

用法:

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
}

So I went ahead and wrote an expression visitor that replaces the variable references with the actual value. It wasn't so hard to do after all.

Usage:

var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression);

The class:

It inherits from ExpressionVisitor which came from the code samples on this page because in .NET 3.0 it is internal. In .NET 4.0 the class is public but might require some changes to this class.

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文