Подтвердить что ты не робот

Что скомпилировано в С# лямбда? Стек-кадр, экземпляр анонимного типа или?

Что скомпилировано в С# лямбда? Стек-кадр, экземпляр анонимного типа или?

Я читал это question. Что в основном отвечает "почему", вы не можете использовать лямбда, когда также используете неявные функции типа. Но этот вопрос направлен на то, какую конструкцию создает компилятор для фактического выполнения кода лямбда. Это вызов метода анонимного типа (что-то вроде анонимных типов, реализующих интерфейс в Java?) Или это просто кадр стека со ссылками на закрытые переменные и принятие сигнатуры параметра? Некоторые лямбда не замыкаются ни на что, так что тогда есть 2 разных результирующих выхода из компиляции.

4b9b3361

Ответ 1

Предполагая, что вы имеете в виду "как делегат", тогда все еще зависит: p, если он фиксирует любые переменные (включая "this", которые могут быть неявными), тогда эти переменные фактически реализуются как поля в генерируемом компилятором типе (не открытый в любом месте), и тело оператора становится методом в этом классе захвата. Если есть несколько уровней захвата, внешний захват снова является полем во внутреннем классе захвата. Но по существу:

int i = ...
Func<int,int> func = x => 2*x*i;

Похоже,

var capture = new SecretType();
capture.i = ...
Func<int,int> func = capture.SecretMethod;

Где:

class SecretType {
    public int i;
    public int SecretMethod(int x) { return 2*x*i; }
}

Это идентично "анонимным методам", но с другим синтаксисом.

Обратите внимание, что методы, которые не фиксируют состояние, могут быть реализованы как статические методы без класса захвата.

Деревья выражений, с другой стороны... Сложнее объяснить: p

Но (у меня нет компилятора, так что несите меня):

int i = ...
Expression<Func<int,int>> func = x => 2*x*i;

Что-то вроде:

var capture = new SecretType();
capture.i = ...
var p = Expression.Parameter("x", typeof(int));  
Expression<Func<int,int>> func = Expression.Lambda<Func<int,int>>(
    Expression.Multiply(
        Expression.Multiply(Expression.Constant(2),p),
        Expression.PropertyOrField(Expression.Constant(capture), "i")
    ), p);

(за исключением использования несуществующей конструкции "memberof", поскольку компилятор может обманывать)

Деревья выражений сложны, но могут быть деконструированы и проверены - например, для перевода в TSQL.

Ответ 2

Лямбда-выражения действительно являются анонимными функциями, но с большей универсальностью. В этих двух статьях, созданных MSDN, есть много информации о лямбда-выражениях, их использовании, о том, какой приоритет имеет оператор =>, какова их связь с анонимными функциями и некоторые дополнительные рекомендации по использованию.

Лямбда-выражения (MSDN)

= > Оператор (MSDN)

Ответ 3

Вот несколько примеров:

public class C
{
    private int field = 0;

    public void M()
    {
        int local = 0;

        Func<int> f1 = () => 0;
        // f1 is a delegate that references a compiler-generated static method in C

        Func<int> f2 = () => this.field;
        // f2 is a delegate that references a compiler-generated instance method in C

        Func<int> f3 = () => local;
        // f3 is a delegate that references an instance method of a compiler-generated nested class in C
    }
}

Ответ 4

Лямбда-выражение является неназванным методом, написанным вместо делегирования. Компилятор преобразует его в:

  • A делегатский экземпляр
  • Дерево выражений , тип Expression<TDelegate>, представляющий код внутри, в обходной объектной модели. Это позволяет интерпретировать лямбда-выражение во время выполнения.

Таким образом, компилятор решает лямбда-выражения, перемещая код выражения в частный метод.