2010-03-25 3 views
2

Je viens de commencer à apprendre à propos de l'itérateur C# mais j'ai été confondu avec le déroulement du programme après avoir lu la sortie du programme. Le foreach avec uniqueVals semble être exécuté deux fois. Ma compréhension est que les premières lignes jusqu'à la ligne avant "Nums in Square: 3" ne devraient pas être là. Quelqu'un peut-il aider à expliquer pourquoi cela arrive?L'itérateur C# est exécuté deux fois lors de la composition de deux méthodes IEnumerable

La sortie est:

 
Unique: 1 
Adding to uniqueVals: 1 
Unique: 2 
Adding to uniqueVals: 2 
Unique: 2 
Unique: 3 
Adding to uniqueVals: 3 

Nums in Square: 3 
Unique: 1 
Adding to uniqueVals: 1 
Square: 1 
Number returned from Unique: 1 
Unique: 2 
Adding to uniqueVals: 2 
Square: 2 
Number returned from Unique: 4 
Unique: 2 
Unique: 3 
Adding to uniqueVals: 3 
Square: 3 
Number returned from Unique: 9 
static class Program 
    { 
     public static IEnumerable<T> Unique<T>(IEnumerable<T> sequence) 
     { 
      Dictionary<T, T> uniqueVals = new Dictionary<T, T>(); 

      foreach (T item in sequence) 
      { 
       Console.WriteLine("Unique: {0}", item); 
       if (!uniqueVals.ContainsKey(item)) 
       { 
        Console.WriteLine("Adding to uniqueVals: {0}", item); 
        uniqueVals.Add(item, item); 
        yield return item; 
        Console.WriteLine("After Unique yield: {0}", item); 
       } 
      } 
     } 

     public static IEnumerable<int> Square(IEnumerable<int> nums) 
     { 
      Console.WriteLine("Nums in Square: {0}", nums.Count()); 
      foreach (int num in nums) 
      { 
       Console.WriteLine("Square: {0}", num); 
       yield return num * num; 
       Console.WriteLine("After Square yield: {0}", num); 
      } 
     } 

     static void Main(string[] args) 
     { 
      var nums = new int[] { 1, 2, 2, 3 }; 
      foreach (int num in Square(Unique(nums))) 
       Console.WriteLine("Number returned from Unique: {0}", num); 
      Console.Read(); 
     } 

    } 

Répondre

2

IEnumerables ne définissent pas de champ pour la taille de la Enumerable, la méthode d'extension Count essaie de le faire pour vous en parcourant toute la collection et dire vous combien d'objets il trouve.

La première itération à travers unique vient de cette ligne:

Console.WriteLine("Nums in Square: {0}", nums.Count());

La deuxième itération vient de votre boucle de foreach comme prévu.

0

Je crois que cette ligne est la cause de votre confusion:

Console.WriteLine("Nums in Square: {0}", nums.Count()); 

IEnumerable Interface <T> n'a pas en fait une méthode de comptage. La méthode Count est ce que l'on appelle une méthode d'extension. Essentiellement, c'est une méthode statique qui fonctionne sur les membres publiquement visibles de IEnumerable <T>. La façon dont cela fonctionne est de parcourir toute la collection et de compter le nombre d'éléments au fur et à mesure. C'est pourquoi vous l'énumérez deux fois: une fois pour la méthode Count() et une fois dans votre boucle foreach.

+0

Notez que Enumerable.Count() est assez intelligent pour utiliser ICollection .Count' et 'ICollection.Count' directement si possible - il ne * itate pas toujours. –

+0

Merci pour l'info. Je ne le savais pas. –

0

Tant le comte() et le foreach sont à l'origine du enumerater pour exécuter votre méthode

Voici une solution/pirater pour vous

public static IEnumerable<int> Square(IEnumerable<int> nums) 
    { 
     var list = nums.ToList(); 
     Console.WriteLine("Nums in Square: {0}", list.Count); 
     foreach (int num in list) 
     { 
      Console.WriteLine("Square: {0}", num); 
      yield return num * num; 
      Console.WriteLine("After Square yield: {0}", num); 
     } 
    } 
Questions connexes