35 votes

Pourquoi ces sorties linq sont-elles différentes ?

1ère déclaration :

IEnumerable<char> query = "Not what you might expect";

query = query.Where (c => c != 'a');
query = query.Where (c => c != 'e');
query = query.Where (c => c != 'i');
query = query.Where (c => c != 'o');
query = query.Where (c => c != 'u');

Sortie de String.Join("", query) : "Nt wht y mght xpct"

2ème déclaration :

query = "Not what you might expect";

foreach (char vowel in "aeiou")
    query = query.Where (c => c != vowel);

Sortie de String.Join("", query) : "Not what yo might expect"

Les résultats de ces déclarations sont différents. Quelqu'un peut-il expliquer pourquoi ?

57voto

Botz3000 Points 23640

Si vous utilisez une version de C# inférieure à 5.0 (où ce problème a été corrigé), c'est la raison :

Le lambda dans votre requête capture la variable de la boucle vowel .
Parce que Linq aime utiliser l'exécution différée, la valeur de cette référence n'est pas lue avant que la requête ne soit exécutée (en l'itérant), c'est-à-dire après que la fonction foreach La boucle est terminée. À ce moment-là, la valeur la plus récente de vowel est u c'est pourquoi vous obtenez un résultat inattendu.

Vous pouvez contourner ce problème en copiant la valeur dans une autre variable temporaire (ou en passant à C# 5.0).

Essayez ça :

query = "Probably what you might expect";

foreach (char vowel in "aeiou") {
    char currentVowel = vowel;
    query = query.Where (c => c != currentVowel );
}

13voto

Honza Brestan Points 3316

C'est parce que vous créez une fermeture sur l'élément vowel variable, qui évolue dans le temps. Stockez sa valeur dans une variable séparée et cela fonctionnera :

query = "Not what you might expect";

foreach (char vowel in "aeiou")
{
    var current = vowel;
    query = query.Where (c => c != current);
}

11voto

Hamlet Hakobyan Points 19023

Lisez sur la fermeture. Si vous utilisez .NET 4.0 et ci-dessous vous obtiendrez un résultat différent. Dans .NET 4.5 ce comportement est modifié (corrigé). Voir aussi comment le compilateur développe foreach .

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