【问题标题】:Expression Trees in C#C# 中的表达式树
【发布时间】:2017-05-07 02:30:46
【问题描述】:

这是我第一次探索表达式树。我有几个基本的疑问。

所以本质上,一个表达式只需要一个 lambda 表达式。 Ans 然后我们可以 Compile() 将 lambda 表达式编译为 MSIL 代码,然后返回一个通用委托。我们可以按原样调用返回的委托。我的理解正确吗?

如果这是我想要达到的目标:((10*5)+(9/4))

BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, Expression.Constant(10), Expression.Constant(5));//(10*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);//((10*5)+(9/4))

所以此时我们已经制作了 lambda expression body 。现在要将其转换为full lambda expression,我们需要调用

Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());

我没有得到这部分。这也不起作用。

为什么是Func&lt;int,int&gt;

是不是内部表达式只接受 int 作为参数,而整个表达式将返回一个 int?

显然这不起作用。生成的 lambda 看起来如何?

我得到了整个画面?如何使这项工作?

【问题讨论】:

  • 这也不起作用。,它有什么作用?它会给你一个错误吗?什么错误?

标签: c# .net lambda code-generation expression-trees


【解决方案1】:
Expression.Lambda<Func<int, int>>(b4).Compile()

Func&lt;int,int&gt; 是 lambda 的签名,它采用单个 int 参数并返回 int。您的 lambda 具有不同的签名。

显然这不起作用。

您的 lambda 不带任何参数,因此您需要 Func&lt;int&gt;

生成的 lambda 是什么样子的?

生成的 lambda 是一个可调用对象。如果您想评估返回的表达式,请强制转换并调用它,如下所示:

var compiledLambda = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
Console.WriteLine(compiledLambda());
//                              ^^

如预期的那样,上面打印出52

Demo 1.

如果您想创建一个Func&lt;int,int&gt;,请在您的表达式中添加一个参数,例如将其设为(p*5)+(9/4),其中pint 参数:

ParameterExpression p = Expression.Parameter(typeof(int));
BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, p, Expression.Constant(5));//(p*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);
var compiledLambda = (Func<int,int>)Expression.Lambda<Func<int,int>>(b4, new[] {p}).Compile();
Console.WriteLine(compiledLambda(10)); // Prints 52
Console.WriteLine(compiledLambda(8));  // Prints 42

Demo 2.

【讨论】:

    【解决方案2】:

    你可以像这样创建你的 lambda 表达式:

    LambdaExpression lb = Expression.Lambda(b4);
    

    然后您可以将此表达式编译为委托:

    Delegate dlg = lb.Compile();
    

    然后将此委托转换为Func&lt;int&gt;

    Func<int> f = (Func<int>)dlg;
    

    你可以像往常一样使用它:

    Console.WriteLine(f()); // 52
    

    通用方式也有效。为什么你使用Func&lt;int,int&gt;?您的表达式不接受任何输入并返回单个 int

    Func<int> f = Expression.Lambda<Func<int>>(b4);
    

    通用参数导致 LambdaExpressionCompile 方法返回 Func&lt;int&gt; 而不是您需要再次转换的 Delegate

    【讨论】:

      【解决方案3】:

      使用:

      Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());
      

      您实际上使用 Console.WriteLine(object) 重载打印它,它会打印参数的 Type 的名称。

      因为这条线:

      Expression.Lambda<Func<int>>(b4).Compile();
      

      只编译 lambda 并为您提供delegate - 不是它的调用结果

      您需要调用已编译的 lambda 并仅打印结果:

      Func<int> result = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
      Console.WriteLine(result());
      

      还请注意,您尝试将delegate 编译为Func&lt;int,int&gt;,它采用int 参数并提供int 结果,但您的代码不需要参数,因此您需要使用Func&lt;int&gt;.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-03
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-06
        相关资源
        最近更新 更多