Suche…


Bemerkungen

Verschlüsse

Lambda-Ausdrücke erfassen implizit die verwendeten Variablen und erzeugen eine Schließung . Ein Abschluss ist eine Funktion zusammen mit einem Zustandskontext. Der Compiler generiert einen Abschluss, wenn ein Lambda-Ausdruck einen Wert aus dem umgebenden Kontext "umschließt".

ZB wenn das Folgende ausgeführt wird

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

safeApplyFilterPredicate bezieht sich auf ein neu erstelltes Objekt, das einen privaten Verweis auf den aktuellen Wert des filterer hat und dessen Invoke Methode sich so verhält

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

Dies kann wichtig sein, denn solange der Verweis auf den Wert in safeApplyFilterPredicate beibehalten wird, gibt es einen Verweis auf das Objekt, auf das sich der filterer aktuell bezieht. Dies hat Auswirkungen auf die Garbage Collection und kann zu einem unerwarteten Verhalten führen, wenn das Objekt, auf das der filterer aktuell verweist, mutiert ist.

Auf der anderen Seite können Verschlüsse verwendet werden, um absichtlich einen Effekt abzukapseln, um ein Verhalten zu kapseln, das Verweise auf andere Objekte beinhaltet.

Z.B

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

Verschlüsse können auch zum Modellieren von Zustandsmaschinen verwendet werden:

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

Grundlegende Lambda-Ausdrücke

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

Grundlegende Lambda-Ausdrücke mit 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"}

Verwenden der Lambda-Syntax zum Erstellen eines Abschlusses

Siehe Anmerkungen zur Erörterung von Schließungen. Angenommen, wir haben eine Schnittstelle:

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

und dann wird folgendes ausgeführt:

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

machineClosure bezieht sich jetzt auf eine Funktion von int bis int , die im Hintergrund die Instanz von IMachine verwendet, auf die sich die machine bezieht, um die Berechnung durchzuführen. Auch wenn die Referenz machine außerhalb des Bereichs geht, solange das machineClosure Objekt beibehalten wird, das ursprüngliche IMachine wird beispielsweise als Teil einer ‚Schließung‘ zurückgehalten wird, automatisch durch den Compiler definiert.

Achtung: Dies kann bedeuten, dass der gleiche Funktionsaufruf zu unterschiedlichen Zeitpunkten unterschiedliche Werte zurückgibt (z. B. in diesem Beispiel, wenn die Maschine eine Summe ihrer Eingaben enthält). In vielen Fällen kann dies unerwartet sein und ist für jeden Code in einem funktionalen Stil zu vermeiden - versehentliche und unerwartete Schließungen können Fehler verursachen.

Lambda-Syntax mit Anweisungsblockkörper

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

Lambda-Ausdrücke mit 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow