2008-10-22 4 views
48

je en train d'écrire un code rapide et remarqué cette erreur de complierPourquoi est-il mauvais d'utiliser une variable d'itération dans une expression lambda

En utilisant la variable d'itération dans une expression lambda peut avoir des résultats inattendus.
Au lieu de cela, créez une variable locale dans la boucle et affectez-lui la valeur de la variable d'itération.

Je sais ce que cela signifie et je peux facilement le réparer, ce n'est pas grave.
Mais je me demandais pourquoi c'est une mauvaise idée d'utiliser une variable d'itération dans un lambda?
Quels problèmes puis-je causer plus tard?

+0

liée: http://stackoverflow.com/questions/190227/building-a-linq-query-programatically-without-local-variables-tricking-me – nawfal

+0

mieux si vous donnez un exemple où cela fonctionne réellement/donne le bon résultat! par exemple regarder le résultat ici http://pastebin.com/raw/FghmXkby ce n'est pas bien .. toujours le même mauvais résultat. – barlop

Répondre

50

Moins ider ce code:

List<Action> actions = new List<Action>(); 

for (int i=0; i < 10; i++) 
{ 
    actions.Add(() => Console.WriteLine(i)); 
} 

foreach (Action action in actions) 
{ 
    action(); 
} 

Qu'attendriez-vous de cette impression? La réponse évidente est 0 ... 9 - mais en réalité il imprime 10, dix fois. C'est parce qu'il n'y a qu'une seule 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 de VB.NET plutôt que de C#. Je crois que VB.NET a des règles encore plus compliquées, en raison de la façon dont les variables conservent leurs valeurs à travers les itérations. This post by Jared Parsons donne des informations sur le type de difficultés rencontrées - bien que cela remonte à 2007, donc le comportement réel peut avoir changé depuis lors.

+6

En deux mots: lambda ne sont pas nécessairement évalués en boucle, et quand ils sont appelés, la variable d'itération peut être hors de portée, non allouée, ou avec sa valeur finale (même au-delà de la limite de boucle). – BertuPG

+8

@BertuPG: Parmi ces deux mots, quels étaient ceux auxquels vous pensiez? ;) –

+0

@Joh: oh ... ouais ... alors laissez-moi remplacer "mots" par "phrases" ^^ – BertuPG

6

En supposant que vous voulez dire C# ici.

C'est à cause de la façon dont le compilateur implémente les fermetures. L'utilisation d'une variable d'itération peut causer un problème avec l'accès à une fermeture modifiée (notez que j'ai dit 'ne peut' pas 'causer' un problème parce que parfois cela ne se produit pas en fonction de quoi d'autre est dans la méthode, vouloir accéder à la fermeture modifiée).

Plus d'infos:

http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx

Encore plus d'info:

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

+1

Ce n'est pas "une fermeture par méthode" - c'est plus compliqué que ça. –

+0

Ouais je me rends compte que lire mal - j'essayais de paraphraser la situation rapidement (explique Raymond plus en profondeur). Suppression de la phrase incriminée afin que les gens puissent regarder les liens plus d'informations. –

Questions connexes