Разве 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# не использует эту функциональность в преобразованиях лямбда-выражений в деревья выражений, которые, насколько я знаю, в настоящее время все еще ограничены лямбда-выражениями.

Другие вопросы по тегам