Recherche…


Remarques

Fermetures

Les expressions Lambda captureront implicitement les variables utilisées et créeront une fermeture . Une fermeture est une fonction associée à un contexte d'état. Le compilateur générera une fermeture chaque fois qu'une expression lambda «enfermera» une valeur de son contexte environnant.

Par exemple, lorsque ce qui suit est exécuté

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

safeApplyFilterPredicate fait référence à un objet nouvellement créé qui a une référence privée à la valeur actuelle du filterer et dont la méthode Invoke se comporte comme

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

Cela peut être important, car tant que la référence à la valeur maintenant dans safeApplyFilterPredicate est conservée, il y aura une référence à l'objet auquel le filterer fait actuellement référence. Cela a un effet sur la récupération de place et peut provoquer un comportement inattendu si l'objet auquel le filterer fait actuellement référence est muté.

D'un autre côté, les fermetures peuvent être utilisées pour limiter délibérément un comportement impliquant des références à d'autres objets.

Par exemple

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

Les fermetures peuvent également être utilisées pour modéliser des machines à états:

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

Expressions lambda de 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

Expressions lambda de base avec 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"}

Utiliser la syntaxe lambda pour créer une fermeture

Voir les remarques pour la discussion des fermetures. Supposons que nous ayons une interface:

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

et puis ce qui suit est exécuté:

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

Maintenant, machineClosure fait référence à une fonction de int à int , qui derrière les scènes utilise l'instance IMachine laquelle la machine fait référence pour effectuer le calcul. Même si la référence machine est hors de portée, dans la mesure où le machineClosure objet est maintenu, l'original IMachine instance est conservé en tant que partie d'une « fermeture », définie automatiquement par le compilateur.

Attention: cela peut signifier que le même appel de fonction renvoie des valeurs différentes à des moments différents (par exemple, dans cet exemple, si la machine conserve une somme de ses entrées). Dans de nombreux cas, cela peut être inattendu et doit être évité pour tout code dans un style fonctionnel - les fermetures accidentelles et inattendues peuvent être une source de bogues.

Syntaxe Lambda avec corps de bloc d'instructions

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

Expressions lambda avec 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow