47 votes

Extérieur Variable Piège

Qu'est-ce exactement que l'Extérieur de la Variable Piège? Explication et des exemples en C# sont appréciés.

EDIT: l'intégration de Jon Skeet du diktat :)

Eric Lippert sur l'Extérieur Variable Piège

64voto

dtb Points 104373

L ' "Extérieur Variable Piège" se produit lorsqu'un développeur s'attend à ce que la valeur d'une variable d'être capturé par une expression lambda ou délégué anonyme, alors qu'en réalité, la variable est capturé lui-même.

Exemple:

var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
    actions.Add(() => Console.Write("{0} ", i));
}
foreach (var action in actions)
{
    action();
}

Possible sortie n ° 1:

0 1 2 3 4 5 6 7 8 9

Possible sortie n ° 2:

10 10 10 10 10 10 10 10 10 10

Si vous vous attendiez la sortie n ° 1, vous êtes tombé dans le côté Extérieur de la Variable Piège. Vous obtenez de sortie #2.

Correctif:

Déclarer un "Intérieur de la Variable" être capturés à plusieurs reprises au lieu de "l'Extérieur Variable" qui est capturé qu'une seule fois.

var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
    var j = i;
    actions.Add(() => Console.Write("{0} ", j));
}
foreach (var action in actions)
{
    action();
}

Pour plus de détails, voir aussi Eric Lippert du blog.

5voto

heisenberg Points 6120

Quelque chose comme

foreach (var s in strings)
    var x = results.Where(r => (r.Text).Contains(s));

Ne donnera pas les résultats que vous attendez, parce que le Contenant n'est pas exécutée pour chaque itération. L'attribution à une variable temporaire à l'intérieur de la boucle résoudre ce problème, cependant.

1voto

TrueWill Points 14855

@dtb est correcte (gros +1), mais il est important de noter que cela s'applique uniquement si le champ d'application de la fermeture s'étend en dehors de la boucle. Par exemple:

var objects = new []
    {
        new { Name = "Bill", Id = 1 },
        new { Name = "Bob", Id = 5 },
        new { Name = "David", Id = 9 }
    };

for (var i = 0; i < 10; i++)
{
    var match = objects.SingleOrDefault(x => x.Id == i);

    if (match != null)
    {
        Console.WriteLine("i: {0}  match: {1}", i, match.Name);
    }
}

Ce sera d'impression:

j': 1 match: le projet de Loi
j': 5 match: Bob
j': 9 match: David

ReSharper vais mettre en garde contre "l'Accès à l'modifié fermeture", qui peut être ignoré dans ce cas.

0voto

Heather Points 1423

Cet article, d'expliquer le concept de fermetures est utile:

http://en.wikipedia.org/wiki/Closure_(computer_science)

Aussi, cet article est vraiment bon à partir d'un plus spécifiques C# de mise en œuvre:

http://blogs.msdn.com/b/abhinaba/archive/2005/08/08/448939.aspx

De toute façon, le tl;lr, c'est que la portée des variables est tout aussi important à anonyme de délégué ou d'expressions lambda, qu'est-ce n'importe où ailleurs dans votre code, le comportement n'est pas aussi évident.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X