Sök…


Anmärkningar

nedläggningar

Lambda-uttryck kommer implicit att fånga variabler som används och skapa en stängning . En nedläggning är en funktion tillsammans med viss statlig kontext. Kompilatorn genererar en stängning närhelst ett lambda-uttryck "stänger" ett värde från dess omgivande sammanhang.

Exempelvis när följande körs

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

safeApplyFilterPredicate hänvisar till ett nyligen skapat objekt som har en privat referens till det aktuella värdet för filterer , och vars Invoke metod fungerar som

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

Detta kan vara viktigt, eftersom så länge referensen till värdet nu i safeApplyFilterPredicate upprätthålls kommer det att finnas en hänvisning till det objekt som filterer närvarande hänvisar till. Detta påverkar skräpuppsamlingen och kan orsaka oväntat beteende om objektet som filterer närvarande hänvisar till är muterat.

Å andra sidan kan stängningar användas för avsiktlig effekt för att kapsla in ett beteende som involverar referenser till andra objekt.

T.ex

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

Stängningar kan också användas för att modellera tillståndsmaskiner:

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

Grundläggande lambda-uttryck

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

Grundläggande lambda-uttryck med 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"}

Använda lambda-syntax för att skapa en nedläggning

Se anmärkningar för diskussion om nedläggningar. Anta att vi har ett gränssnitt:

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

och sedan exekveras följande:

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

Nu hänvisar machineClosure till en funktion från int till int , som bakom kulisserna använder IMachine instansen som machine refererar till för att utföra beräkningen. Även om machine går ut ur räckvidd, så länge som machineClosure objektet bibehålls, den ursprungliga IMachine instans kommer att behållas som en del av en 'förslutning', automatiskt definieras av kompilatorn.

Varning: detta kan innebära att samma funktionssamtal returnerar olika värden vid olika tidpunkter (t.ex. i detta exempel om maskinen har en summa av sina ingångar). I många fall kan detta vara oväntat och ska undvikas för alla kod i funktionell stil - oavsiktliga och oväntade stängningar kan vara en källa till buggar.

Lambda syntax med uttalande block body

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

Lambda-uttryck med 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow