Zoeken…


Opmerkingen

sluitingen

Lambda-expressies zullen impliciet gebruikte variabelen vastleggen en een afsluiting creëren . Een sluiting is een functie samen met een bepaalde toestandscontext. De compiler genereert een afsluiting wanneer een lambda-expressie een waarde uit de omliggende context 'omsluit'.

Bijvoorbeeld wanneer het volgende wordt uitgevoerd

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

safeApplyFilterPredicate verwijst naar een nieuw gemaakt object dat een privéverwijzing heeft naar de huidige waarde van filterer en waarvan de Invoke methode zich gedraagt als

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

Dit kan belangrijk zijn, want zolang de verwijzing naar de waarde nu in safeApplyFilterPredicate wordt gehandhaafd, is er een verwijzing naar het object waarnaar het filterer momenteel verwijst. Dit heeft effect op het verzamelen van afval en kan onverwacht gedrag veroorzaken als het object waarnaar het filterer momenteel verwijst, is gemuteerd.

Aan de andere kant kunnen sluitingen worden gebruikt om het effect te beraadslagen om een gedrag in te kapselen dat referenties naar andere objecten omvat.

Eg

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

Sluitingen kunnen ook worden gebruikt om state machines te modelleren:

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

Basis lambda-uitdrukkingen

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

Basis lambda-uitdrukkingen met 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"}

Lambda-syntaxis gebruiken om een sluiting te maken

Zie opmerkingen voor bespreking van sluitingen. Stel dat we een interface hebben:

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

en dan wordt het volgende uitgevoerd:

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

Nu verwijst machineClosure naar een functie van int tot int , die achter de schermen de IMachine instantie gebruikt waarnaar de machine verwijst om de berekening uit te voeren. Zelfs als de referentie machine buiten het bereik valt, mits de machineClosure object wordt gehandhaafd, de oorspronkelijke IMachine instantie wordt gehandhaafd als onderdeel van een 'afsluiting', automatisch gedefinieerd door de compiler.

Waarschuwing: dit kan betekenen dat dezelfde functieaanroep verschillende waarden op verschillende tijdstippen retourneert (bijvoorbeeld in dit voorbeeld als de machine een som van zijn ingangen bewaart). In veel gevallen kan dit onverwacht zijn en moet worden vermeden voor elke code in een functionele stijl - onopzettelijke en onverwachte sluitingen kunnen een bron van fouten zijn.

Lambda-syntaxis met body met statement block

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

Lambda-expressies met 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow