Поиск…


замечания

Затворы

Лямбда-выражения будут неявно захватывать используемые переменные и создавать закрытие . Закрытие - это функция, а также некоторый контекст состояния. Компилятор будет генерировать замыкание всякий раз, когда выражение лямбда «окружает» значение из его окружающего контекста.

Например, когда выполняется следующее

Func<object, bool> safeApplyFiltererPredicate = o => (o != null) && filterer.Predicate(i);

safeApplyFilterPredicate относится к вновь созданному объекту, который имеет частную ссылку на текущее значение filterer и метод Invoke которого ведет себя как

o => (o != null) && filterer.Predicate(i);

Это может быть важно, потому что до тех пор , как ссылка на значение в настоящее время в safeApplyFilterPredicate поддерживается, будет ссылка на объект , который filterer в настоящее время относится к. Это оказывает влияние на сборке мусора, и может привести к непредсказуемым результатам , если объект , который filterer в настоящее время относится к мутирует.

С другой стороны, замыкания могут использоваться для преднамеренного эффекта, чтобы инкапсулировать поведение, которое включает ссылки на другие объекты.

Например

var logger = new Logger();
Func<int, int> Add1AndLog = i => {
    logger.Log("adding 1 to " + i);
    return (i + 1);
};

Закрытие также может использоваться для моделирования состояний машин:

Func<int, int> MyAddingMachine() {
    var i = 0;
    return x => i += x;
};

Основные лямбда-выражения

Func<int, int> add1 = i => i + 1;

Func<int, int, int> add = (i, j) => i + j;

// Behaviourally equivalent to:

int Add1(int i)
{
    return i + 1;
}

int Add(int i, int j)
{
    return i + j;
}

...

Console.WriteLine(add1(42)); //43
Console.WriteLine(Add1(42)); //43
Console.WriteLine(add(100, 250)); //350
Console.WriteLine(Add(100, 250)); //350

Основные лямбда-выражения с LINQ

// assume source is {0, 1, 2, ..., 10}

var evens = source.Where(n => n%2 == 0);
// evens = {0, 2, 4, ... 10}

var strings = source.Select(n => n.ToString());
// strings = {"0", "1", ..., "10"}

Использование синтаксиса лямбда для создания замыкания

См. Замечания для обсуждения замыканий. Предположим, что у нас есть интерфейс:

public interface IMachine<TState, TInput>
{
    TState State { get; }
    public void Input(TInput input);
}

и затем выполняется следующее:

IMachine<int, int> machine = ...;
Func<int, int> machineClosure = i => {
    machine.Input(i);
    return machine.State;
};

Теперь machineClosure ссылается на функцию от int до int , которая за кулисами использует экземпляр IMachine который ссылается machine , чтобы выполнить вычисление. Даже если ссылка machine выходит из области видимости, до тех пор , как machineClosure объект сохраняется, оригинальный IMachine экземпляр будет сохранена как часть «закрытия», автоматически определяется компилятором.

Предупреждение: это может означать, что один и тот же вызов функции возвращает разные значения в разное время (например, в этом примере, если машина хранит сумму своих входов). Во многих случаях это может быть неожиданным, и его следует избегать для любого кода в функциональном стиле - случайные и неожиданные закрытия могут быть источником ошибок.

Синтаксис Lambda с телом блока оператора

Func<int, string> doubleThenAddElevenThenQuote = i => {
    var doubled = 2 * i;
    var addedEleven = 11 + doubled;
    return $"'{addedEleven}'";
};

Лямбда-выражения с System.Linq.Expressions

Expression<Func<int, bool>> checkEvenExpression = i => i%2 == 0;
// lambda expression is automatically converted to an Expression<Func<int, bool>>


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow