C# Language
Expressions lambda
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>>