Разве LINQ Expression API не предлагает способа создания переменной?
Я хочу подтвердить мое предположение о том, что в API LINQ Expression нет средств для создания выражения, представляющего создание локальной переменной.
Другими словами, вы не можете создать выражение для представления:
int local;
поскольку это оператор объявления переменной, а API не поддерживает лямбда-выражения оператора. Единственное состояние, с которым может работать лямбда-выражение, представленное API-интерфейсом выражений LINQ (а не экземпляром делегата), - это параметры, которые он получает, и захваченные переменные, которые он получает через замыкание.
Правильно ли мое предположение (основанное на нескольких месяцах применения LINQ Expression API)?
2 ответа
Ложь. Для этого существуют некоторые перегрузки Expression.Block.
Верно то, что вы не можете создать лямбда-выражение с помощью компилятора C#, который имеет переменную, но это является ограничением компилятора.
Так что вы не можете
Expression<Func<int>> exp = () => {
int v = 1;
return v;
};
но вы можете
var variable = Expression.Variable(typeof(int));
var lambda = Expression.Lambda<Func<int>>(
Expression.Block(
new[] { variable },
Expression.Assign(variable, Expression.Constant(1)),
variable)); // With lambda expressions, there is an implicit
// return of the last value "loaded" on the stack
поскольку это оператор объявления переменной, а API не поддерживает лямбда-выражения оператора.
Это было верно в.NET < 4.0 . В.NET 4.0 добавлена Microsoft Expression
методы для создания почти всего, что может присутствовать в теле метода (есть некоторые пропущенные "вещи", такие как небезопасные ключевые слова / операторы кода, плюс есть примитивы, но нет сложных конструкций, таких как for
или же lock
, который может быть построен поверх других конструкций). Обратите внимание, что 90% этих добавок несовместимы с LINQ-to-SQL/EF.
Ну, вы можете использовать Expression.Block
объявить блок, который содержит локальные переменные...
Например:
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
var x = Expression.Variable(typeof(int), "x");
var assignment1 = Expression.Assign(x, Expression.Constant(1, typeof(int)));
var assignment2 = Expression.Assign(x, Expression.Constant(2, typeof(int)));
var block = Expression.Block(new[] { x }, new[] { assignment1, assignment2 });
}
}
Это создает дерево выражений, эквивалентное:
{
int x;
x = 1;
x = 2;
}
Компилятор C# не использует эту функциональность в преобразованиях лямбда-выражений в деревья выражений, которые, насколько я знаю, в настоящее время все еще ограничены лямбда-выражениями.