Ricerca…


Osservazioni

chiusure

Le espressioni lambda catturano implicitamente le variabili utilizzate e creano una chiusura . Una chiusura è una funzione insieme a un contesto statale. Il compilatore genererà una chiusura ogni volta che un'espressione lambda "racchiude" un valore dal suo contesto circostante.

Ad esempio quando viene eseguito quanto segue

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

safeApplyFilterPredicate fa riferimento a un oggetto appena creato che ha un riferimento privato al valore corrente del filterer e il cui metodo Invoke si comporta come

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

Questo può essere importante, poiché finché viene mantenuto il riferimento al valore ora in safeApplyFilterPredicate , ci sarà un riferimento all'oggetto cui si riferisce attualmente il filterer . Ciò ha un effetto sulla garbage collection e può causare comportamenti imprevisti se l'oggetto al quale il filterer riferisce attualmente è mutato.

D'altra parte, le chiusure possono essere utilizzate per deliberare l'effetto di incapsulare un comportamento che implica riferimenti ad altri oggetti.

Per esempio

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

Le chiusure possono anche essere utilizzate per modellare macchine a stati:

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

Espressioni lambda di base

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

Espressioni lambda di base con 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"}

Usare la sintassi lambda per creare una chiusura

Vedi le osservazioni per la discussione delle chiusure. Supponiamo di avere un'interfaccia:

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

e quindi viene eseguito quanto segue:

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

Ora machineClosure fa riferimento a una funzione da int a int , che dietro le quinte usa l'istanza IMachine cui fa riferimento la machine per eseguire il calcolo. Anche se la machine riferimento esce dall'ambito, finché l'oggetto machineClosure viene mantenuto, l'istanza IMachine originale verrà mantenuta come parte di una "chiusura", definita automaticamente dal compilatore.

Attenzione: questo può significare che la stessa chiamata di funzione restituisce valori diversi in momenti diversi (es. In questo esempio se la macchina mantiene una somma dei suoi ingressi). In molti casi, questo può essere inaspettato e deve essere evitato per qualsiasi codice in uno stile funzionale: le chiusure accidentali e inaspettate possono essere una fonte di bug.

Sintassi Lambda con corpo del blocco di istruzioni

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

Espressioni Lambda con 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow