繁体   English   中英

参数和变量如何在 C# 表达式树中实际工作?

[英]How do parameters and variables actually work in C# Expression trees?

老实说,我只是迷路了,我似乎无法理解表达式树语法应该如何应用于 function,并且在尝试创建最简单的 lambdas 时不断出错。

让我们以一个非常基本的 function 为例:你提供一个数字作为参数,它只是将它添加到 0,是的,它没用,但我什至无法让它工作:

public void AddNumber(int number)
    {
        var input = Expression.Parameter(typeof(int), "number");
        var result = Expression.Variable(typeof(int), "result");
        
        var addAssign = Expression.AddAssign(result, input);

        int myExpectedResult = Expression.Lambda<Func<int, int>>(addAssign, input).Compile()(number);
    }

我收到一个错误,因为变量 result 已创建但未定义,这是有道理的。 所以我假设我需要为它分配一些值以使其工作:

public void AddNumber(int number)
    {
        var input = Expression.Parameter(typeof(int), "number");
        var result = Expression.Variable(typeof(int), "result");
        
        var addAssign = Expression.AddAssign(result, input);

        int myExpectedResult = Expression.Lambda<Func<int, int>>(addAssign, input).Compile()(number);
    }

同样的错误,我假设是因为分配没有真正被考虑在内,因为它没有被使用。 但是您也不能将该分配变量用作 AddAssign function 的参数,因此它基本上没有区别。

现在,如果我创建一个块表达式来连续执行两个赋值,这将消除错误,但是,我的“输入”现在总是设置为 0:

        public void AddNumber(int number)
    {
        var input = Expression.Parameter(typeof(int), "number");
        var result = Expression.Variable(typeof(int), "result");

        var blockExpression = Expression.Block(new[] { input, result },
            Expression.Assign(result, Expression.Constant(0)),
            Expression.AddAssign(result, input));

        int myExpectedResult = Expression.Lambda<Func<int, int>>(blockExpression, input).Compile()(number);
    }

您实际上应该如何简单地添加一个参数,创建一个变量,然后为该变量赋值以返回它? 我似乎找不到任何教程可以正确解释如何在不同的 BlockExpressions 中保持参数/变量之间的链接。

非常感谢! 任何帮助表示赞赏!

你非常接近,但AddAssign+= ,所以你试图做一些看起来像

x => x += y

其中y未定义且+=无法写入x

而是尝试对+使用Expression.Add ,对 integer 值使用Expression.Constant

像下面这样的东西应该可以工作:

var paramExp = Expression.Parameter(typeof(int), "x");
var intExp = Expression.Constant(5);

// x + 5
var addExp = Expression.Add(paramExp, intExp);

// x => x + 5
var result = Expression.Lambda<Func<int, int>>(addExp, paramExp).Compile()(3);

Assert.AreEqual(8, result);

在编写表达式树时,我总是发现在尝试使用表达式树编写结果表达式之前先以人类可读的形式编写结果表达式会更容易。

所以第一步是——你想得到什么? number => number + 0吗?

如果是这种情况,那就是 lambda 表达式。 你想要做的是开始将结果表达式解构为更小的表达式部分。 在这种情况下,我们有 lambda 表达式的左侧是number和 lambda 表达式的右侧是number + 0

我们在这里看到了什么? 有一个int类型的参数称为number ,还有一个int类型的常量值,其值为0 这里还有什么 - Add表达式。

所以你首先定义你的参数:
var numberParamer = Expression.Parameter(typeof(int), "number");

然后你定义你的常数:
var constant = Expression.Constant(0);

然后定义添加表达式:
var addExpression = Expression.Add(constant, numberParamer);

最后,lambda:

var lambda = Expression.Lambda<Func<int, int>>(
  addExpression, // the first argument represents right side of the lambda
  numberParamer // the second argument takes a variable number of values, 
                // depending on the number of your parameters on the left side of your lambda. In this case, one
);

现在你可以这样称呼它:
var result = lambda.Compile()(number) ;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM