2009-09-05 9 views
3

J'ai une requête Linq qui ressemble à ceci:résultats inattendus dans la requête Linq

var myPosse = from p1 in people 
      select p1; 
label1.Text = "All my peeps:" + Environment.NewLine; 
foreach (Person p in myPosse) 
{ 
    this.label1.Text += p.ToString() + Environment.NewLine; 
} 

Cela me donne de bons résultats.

Mais quand je fais quelque chose comme ceci:

var myPosse = from p1 in people 
      select p1; 
label1.Text = "All my peeps:" + Environment.NewLine; 
people.Add(new Person{FirstName="Don", LastName="Cash"}); 
foreach (Person p in myPosse) 
{ 
    this.label1.Text += p.ToString() + Environment.NewLine; 
} 

Je le gars 'extra' là-dedans! Comment cela se passe-t-il? Ma variable Linq est définie avant le gars supplémentaire est ajouté.

Répondre

7

Ceci est dû à l'exécution différée, une caractéristique majeure de Linq.

Ce qui est stocké dans var n'est pas réellement un jeu de résultats. C'est en fait le potentiel pour lancer une requête. La requête n'est pas exécutée lorsque la valeur est affectée à une variable. Il fonctionne seulement au besoin et le fait petit à petit.

Ceci est une partie énorme de Linq et est là pour l'amour de l'efficacité. L'exécution différée économise beaucoup de temps et de ressources. B/c il est possible d'abandonner la requête plus tôt et ainsi, nous avons perdu du temps et de la mémoire si nous n'avons pas besoin de la queue. En outre, si l'ensemble de résultats est méga-énorme, il est inefficace. (Pensez à slurping un fichier par rapport à la diffusion dans say, perl ou PHP).

Vous ne pouvez pas vraiment forcer l'exécution immédiate, mais voici une astuce pour l'approximer.

var myPosse = from p1 in people 
      select p1; 
List<Person> theTeam = myPosse.ToList(); 
label1.Text = "All my peeps:" + Environment.NewLine; 
people.Add(new Person{FirstName="Don", LastName="Cash"}); 
foreach (Person p in theTeam) 
{ 
    this.label1.Text += p.ToString() + Environment.NewLine; 
} 

Notez la méthode "ToList()". Dans cette situation, votre requête Linq s'exécute entièrement au moment .ToList(). Votre liste d'origine est conservée dans l'équipe alors que vous avez votre gars 'extra' dans les gens IEnumerable.

3

Lorsque vous parcourez les résultats de la plupart des méthodes d'extension LINQ (mais pas toutes), les résultats ne sont pas réellement calculés jusqu'à ce que vous les utilisiez. Cela est dû à deferred execution.

Ce qui se passe est que LINQ crée un IEnumerable<Person> qui parcourra votre collection "people". Cependant, ce n'est pas une copie de votre collection - elle énumérera comme demandé. Lorsque vous effectuez votre boucle "foreach", plus tard, elle commence réellement à parcourir la collection de personnes - en utilisant les personnes comme c'est à ce moment. Cela signifie que vous aurez votre personne supplémentaire.

Vous pouvez éviter cela en utilisant une extension LINQ qui permettra de créer une copie de vos données:

var myPosse = (from p1 in people 
     select p1).ToList(); // This makes a copy in a new list... 
label1.Text = "All my peeps:" + Environment.NewLine; 
people.Add(new Person{FirstName="Don", LastName="Cash"}); 
foreach (Person p in myPosse) 
{ 
    this.label1.Text += p.ToString() + Environment.NewLine; 
    // Don Cash won't show up now, since it wasn't in the original list when the copy was made 
} 
+0

ne serait pas mieux si vous appelez .Count() sur le myPosse juste après la requête? ce serait mieux que de le convertir en liste: var myPosse = (à partir de p1 dans les gens, sélectionnez p1) .ToList(); myPosse.Count(); –

Questions connexes