Во время моей работы с деревьями выражений в течение нескольких дней теперь, я столкнулся с чем-то, что я нахожу трудными понять; надо надеяться, кто-то сможет так проливает некоторый свет здесь.
Если Вы кодируете Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x;
компилятор будет жаловаться, и Вы не доберетесь нигде. Однако кажется, что при создании одного такого выражения через метод затем, компилятор, кажется, доволен этим и получающиеся работы приложения. Это не имеет смысла, таким образом, я задаюсь вопросом, что продолжается позади занавесок.
Я предполагаю что, под капотом, выражение, возвращенное ConvertExpression
возможно, имеет тип Expression<Func<object, object>>
, который является допустимым типом, но он озадачивает меня, что я не могу использовать Expression<Func<dynamic, dynamic>>
введите в объявлении, и все же я могу использовать его в качестве типа возврата метода. Посмотрите пример ниже.
Большое спасибо!
public class ExpressionExample
{
public void Main()
{
// Doesn't compile:
//Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x;
// Compiles and works - OK
Expression<Func<double, double>> expr2 = x => 2 * x;
Func<double, double> func2 = (Func<double, double>)expr2.Compile();
Console.WriteLine(func2(5.0).ToString()); // Outputs 10
// Compiles and works - ??? This is the confusing block...
Expression<Func<dynamic, dynamic>> expr3 = ConvertExpression(expr2);
Func<dynamic, dynamic> func3 = (Func<dynamic, dynamic>)expr3.Compile();
Console.WriteLine(func3(5.0).ToString()); // Outputs 10
// Side note: compiles and works:
Expression<Func<object, object>> expr4 = x => double.Parse(2.ToString()) * double.Parse(x.ToString());
Func<object, object> func4 = (Func<object, object>)expr4.Compile();
Console.WriteLine(func4(5.0).ToString()); // Outputs 10
}
private Expression<Func<dynamic, dynamic>> ConvertExpression<TInput, TOutput>(Expression<Func<TInput, TOutput>> expression)
{
Expression<Func<object, TInput>> convertToInput = value => (TInput)value;
// The following doesn't compile: var input = Expression.Parameter(typeof(dynamic), "input");
var input = Expression.Parameter(typeof(object), "input");
Expression<Func<TOutput, dynamic>> convertToOutput = value => (dynamic)value;
var body = Expression.Invoke(convertToOutput, Expression.Invoke(expression, Expression.Invoke(convertToInput, input)));
var lambda = Expression.Lambda<Func<dynamic, dynamic>>(body, input);
return lambda;
}
}
Я полагаю, что под капотом выражение, возвращаемое преобразованием, является, возможно, типа
выражения
, который является действительным типом>
Правильный.
Я не могу использовать
Expression
введите декларацию, и все же я могу использовать его в качестве обратного типа метода.>
Эта часть утверждения неверна. Как вы заметите в своем примере, совершенно законно использовать этот тип в декларации локальной переменной.
Чем не является законным, является выполнение динамической операции внутри лямбда, которая преобразуется в тип дерева выражения. Конкретный тип дерева выражения не имеет значения; Что дело в том, что операция динамически.
Ошибка компилятора Я получил, когда я попробовал, был «Ошибка CS1963: дерево выражения может не содержать динамическую операцию». Я изменил проблему строки на выражение
(удаление «операции» из лямбда) и работало! Таким образом, вам разрешено иметь динамику в выражениях, но вы не можете на самом деле выполнять какие-либо «операции» на них. Не очень полезно, я знаю. В моем тестировании даже .ToString ()
считается как операция.