简体   繁体   English

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

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

I'm honestly just lost, I can't seem to make sense of how Expression tree syntax is supposed to function, and keep getting errors trying to create the simplest of lambdas.老实说,我只是迷路了,我似乎无法理解表达式树语法应该如何应用于 function,并且在尝试创建最简单的 lambdas 时不断出错。

Let's take a very basic function: you supply a number as a parameter, and it simply adds that to 0, yes it useless, but I can't even make that work:让我们以一个非常基本的 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);
    }

I get an error because the variable result is created, but not defined, which makes sense.我收到一个错误,因为变量 result 已创建但未定义,这是有道理的。 So I assume I need to assign some value to it to make it work:所以我假设我需要为它分配一些值以使其工作:

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

Same error, I'm assuming because the assign isn't really taken into account as it is not used.同样的错误,我假设是因为分配没有真正被考虑在内,因为它没有被使用。 But you also can't use that assign variable as a parameter for the AddAssign function, so it basically makes no difference.但是您也不能将该分配变量用作 AddAssign function 的参数,因此它基本上没有区别。

Now, if I create a block expression to do both assignements in a row, this will get rid of the error, however, my "input" is now always set to 0:现在,如果我创建一个块表达式来连续执行两个赋值,这将消除错误,但是,我的“输入”现在总是设置为 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);
    }

How are you actually supposed to simply add a parameter, create a variable, then assign a value to that variable to return it?您实际上应该如何简单地添加一个参数,创建一个变量,然后为该变量赋值以返回它? I can't seem to find any tutorial that properly explains how to keep the link between parameters/variables, in different BlockExpressions.我似乎找不到任何教程可以正确解释如何在不同的 BlockExpressions 中保持参数/变量之间的链接。

Thanks a lot!非常感谢! Any help is appreciated!任何帮助表示赞赏!

You're very close, but AddAssign is += , so you were trying to make something that looks like你非常接近,但AddAssign+= ,所以你试图做一些看起来像

x => x += y

where y is not defined and += can't write to x .其中y未定义且+=无法写入x

Instead try using Expression.Add for + , and Expression.Constant for an integer value.而是尝试对+使用Expression.Add ,对 integer 值使用Expression.Constant

Something like the following should work:像下面这样的东西应该可以工作:

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);

When writing expression trees, I always found it easier if I first wrote my result expression in a human readable form before trying to write it using an expression tree.在编写表达式树时,我总是发现在尝试使用表达式树编写结果表达式之前先以人类可读的形式编写结果表达式会更容易。

So the first step is - what are you trying to get?所以第一步是——你想得到什么? Is it number => number + 0 ?number => number + 0吗?

If that's the case, it is a lambda expression.如果是这种情况,那就是 lambda 表达式。 What you want to do it start destructuring the result expression into smaller expression parts.你想要做的是开始将结果表达式解构为更小的表达式部分。 In this case, we have the left side of the lambda expression which is number and the right side of the lambda expression which is number + 0 .在这种情况下,我们有 lambda 表达式的左侧是number和 lambda 表达式的右侧是number + 0

What do we see here?我们在这里看到了什么? There is a parameter of type int called number , and there is a constant value of type int with value 0 .有一个int类型的参数称为number ,还有一个int类型的常量值,其值为0 What else is here - an Add expression.这里还有什么 - Add表达式。

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

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

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

And finally, the lambda:最后,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
);

Now you can call it like:现在你可以这样称呼它:
var result = lambda.Compile()(number) ; var result = lambda.Compile()(number) ;

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

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