Pourquoi est-il mauvais d'utiliser une variable d'itération dans une expression lambda
Je viens d'écrire quelques rapide du code et remarqua que ce complier erreur
À l'aide de la variable d'itération dans une expression lambda peut avoir des résultats inattendus.
Au lieu de cela, créer une variable locale à l'intérieur de la boucle et de lui affecter la valeur de la variable d'itération.
Je sais ce que cela signifie et je peux facilement le fixer, pas une grosse affaire.
Mais je me demandais pourquoi il est une mauvaise idée d'utiliser une variable d'itération dans une lambda?
Quels sont les problèmes que je peux causer plus tard?
- connexes: stackoverflow.com/questions/190227/...
- mieux, si vous donnez un exemple où cela fonctionne réellement / donne le bon résultat! par exemple regardez le résultat ici pastebin.com/raw/FghmXkby ce n'est pas bon.. toujours le même résultat erroné.
- Une mise en œuvre de façon étonnamment intuitive qu'il y a de 500 000 questions et 9 000 posts à ce sujet... qu'est-ce que cela, C++?
Vous devez vous connecter pour publier un commentaire.
Considérer ce code:
Qu'attendez-vous cette impression? La réponse évidente est de 0...9 - mais en réalité, il imprime 10, dix fois. C'est parce qu'il y a juste une variable qui est capturée par tous les délégués. C'est ce genre de comportement qui est inattendu.
EDIT: je viens de voir que vous parlez VB.NET plutôt que de C#. Je crois VB.NET a même des règles plus compliquées, en raison de la façon dont les variables de maintenir leurs valeurs à travers des itérations. Ce post par Jared Parsons donne quelques informations sur le type de difficultés rencontrées - même si il est de retour à partir de 2007, de sorte que le comportement réel peuvent avoir changé depuis.
En supposant que tu veux dire C# ici.
C'est à cause de la manière dont le compilateur met en œuvre des fermetures. À l'aide d'une variable d'itération peut cause d'un problème d'accès à une modification de la fermeture (notez que j'ai dit 'peut' pas 'sera' cause un problème, parce que parfois, il n'arrive pas en fonction de ce que le reste est dans la méthode, et parfois vous voulez vraiment pour accéder à la modification de la fermeture).
Plus d'infos:
http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx
Encore plus d'infos:
http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx
Théorie de Fermetures .NET
Variables locales: portée et durée de vie (plus de fermetures) (Archivé 2010)
(L'emphase est mienne)
Quand vous pensez à la façon des fermetures de travail .NET, je conseille de garder ces points de balle à l'esprit, c'est ce que les concepteurs ont dû travailler avec quand ils ont été la mise en œuvre de cette fonctionnalité:
Delegate
s.Func(Of T)
(c'est à dire,Delegate
) des cas ont aucun moyen de stocker les paramètres passés en eux.Func(Of T)
ne stocker l'instance de la classe la méthode est une méthode de. C'est l'avenue la .NET framework utilisé pour se "souvenir" de paramètres passés dans les expressions lambda.Eh bien nous allons prendre un coup d'oeil!
Exemple De Code:
Donc, disons que vous avez écrit un code comme ceci:
Vous attend peut-être le code pour imprimer 0,1,2,3, mais en fait elle imprime 4,4,4,4, c'est parce que
indexParameter
a été "capturé" dans le champ d'application deSub VBDotNetSample()
champ d'application, et non pas dans leFor
boucle portée.Décompilé Exemple De Code
Personnellement, j'ai vraiment envie de voir ce genre de code que le compilateur a généré pour cela, alors je suis allé de l'avant et utilisé JetBrains DotPeek. J'ai pris le code généré par le compilateur, et de la main traduit de retour à VB.NET.
Commentaires et les noms de variables de la mine. Le code a été simplifié légèrement dans les moyens qui ne affecte pas le comportement du code.
Noter qu'il n'existe qu'une seule instance de
closureHelperClass
pour l'ensemble du corps deSub CompilerGenerated
, donc il est impossible que la fonction d'impression de l'intermédiaireFor
boucle valeurs de l'indice de 0,1,2,3 (il n'y a pas de place pour stocker ces valeurs). Le code affiche seulement 4, la valeur de l'indice final (après laFor
boucle) quatre fois.Notes de bas de page:
"Mais jrh pourquoi avez-vous poster une réponse tardive?"
closureHelperClass
, on dirait qu'il est en raison d'un bogue dans Visual Studio, enregistrez souvent lors de l'utilisation de renommer / refactoriser!