2016-12-21 9 views
4

Впервые я изучаю деревья выражений. У меня есть несколько основных сомнений.Деревья выражений в C#

По существу, выражение принимает только лямбда-выражение. Ans, тогда мы можем скомпилировать() выражение лямбда для кода 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<int,int>?

Похоже, что внутренние выражения будут принимать только int как param, и все выражение вернет int?

Очевидно, что это не работает. Как выглядит сгенерированная лямбда?

Я получаю картину всего изображения? Как это сделать?

+1

* И это не работает также *, что он делает? Это дает вам ошибку? Какая ошибка? –

ответ

6
Expression.Lambda<Func<int, int>>(b4).Compile() 

Func<int,int> является подпись для лямбды, которые принимают один параметр int и возвращающих int. У вашей лямбды есть другая подпись.

Очевидно, что это не работает.

Ваш lambda не принимает никаких параметров, поэтому вам нужно Func<int>.

Как выглядит сгенерированная лямбда?

Сгенерированная лямбда - объект, подлежащий вызову. Если вы хотите, чтобы оценить выражение, которое вы получите обратно, бросание и назвать его, например:

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

Вышеуказанные отпечатки 52, как и ожидалось.

Demo 1.

Если вы хотели бы сделать Func<int,int>, добавить параметр к вашему выражению, например, сделать его (p*5)+(9/4) где p является int параметр:.

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.

1

Использование:

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

вы на самом деле печатать с Console.WriteLine(object) перегрузки, который печатает имя Type аргумента.

с линии:

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

компилирует только лямбда и предоставляет Вам delegate - результат не его призывание в.

Вы должны вызвать скомпилированный лямбда и печать только результат:

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

отметить также, что вы пытаетесь скомпилировать delegate как Func<int,int> который принимает int аргумент и дает результат int, но ваш код не требует аргумента, поэтому вам нужно использовать Func<int>.

4

Вы можете создать лямбда-выражение так:

LambdaExpression lb = Expression.Lambda(b4); 

Вы можете скомпилировать это выражение делегата:

Delegate dlg = lb.Compile(); 

И бросил этот делегат на Func<int>:

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

И вы можете использовать это как обычно:

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

Общий способ работы тоже. Почему do вы используете Func<int,int>? Ваше выражение не имеет никакого ввода и возвращает один int:

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

Родовое аргумент приводит к LambdaExpression с Compile метод, который возвращает Func<int> вместо Delegate, что вы должны снова бросить.