Maison > Article > développement back-end > Pourquoi toutes les expressions lambda dans une boucle foreach capturent-elles la même variable au lieu de leurs valeurs individuelles ?
Variables capturées dans les expressions Lambda : démystifier le mystère de la "variable de boucle foreach"
Considérez le code déroutant ci-dessous, qui vise à créer une liste de méthodes qui accueillent différents types de données :
public class MyClass { public delegate string PrintHelloType(string greeting); public void Execute() { Type[] types = new Type[]{typeof(string), typeof(float), typeof(int)}; List<PrintHelloType> helloMethods = new List<PrintHelloType>(); foreach (var type in types) { var sayHello = new PrintHelloType(greeting => SayGreetingToType(type, greeting)); helloMethods.Add(sayHello); } foreach (var helloMethod in helloMethods) { Console.WriteLine(helloMethod("Hi")); } } public string SayGreetingToType(Type type, string greetingText) { return greetingText + " " + type.Name; } }
Cependant, lorsque vous exécutez ce code, vous rencontrez un résultat inattendu : il imprime trois fois "Hi Int32", au lieu du "Hi String" prévu, "Hi Single", "Salut Int32". Que se passe-t-il ici ?
La subtilité des fermetures et des variables capturées
La clé pour comprendre ce comportement réside dans le concept de fermetures et de variables capturées. Lorsqu'une expression lambda est créée, elle capture les variables de sa portée environnante. Dans ce cas, l'expression lambda capture la variable de type de la boucle foreach.
Variables de boucle capturées : un piège
Essentiellement, la variable capturée n'est pas la valeur de type, mais la variable elle-même. Au fur et à mesure que la boucle progresse, la variable de type change, tandis que les expressions lambda font toujours référence à la même variable capturée.
Corriger le problème
Pour obtenir le comportement souhaité, il est nécessaire de créer une nouvelle variable dans la boucle pour capturer la valeur souhaitée. Voici comment modifier le code :
foreach (var type in types) { var newType = type; var sayHello = new PrintHelloType(greeting => SayGreetingToType(newType, greeting)); helloMethods.Add(sayHello); }
En capturant newType au lieu du type, les expressions lambda ont désormais une référence constante à la valeur souhaitée et le résultat attendu est obtenu.
Conclusion
Comprendre les subtilités des fermetures et des variables capturées est essentiel lorsque l'on travaille avec des expressions lambda. En étant attentif à ces mécanismes, vous pouvez éviter les comportements inattendus et garantir que votre code fonctionne comme prévu.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!