2016-05-13 6 views
0

Ich versuche, Ausbeute Rendite mit IEnumerator zu verstehen. Nachdem ich das folgende einfache Beispiel ausprobiert habe, habe ich festgestellt, dass die letzte Methode in der Kette zuerst ausgeführt wird. Was ich nicht erwartet hatte.Ertragsrückgabe ändert die Reihenfolge der verketteten Aufrufmethoden

public static void Example() 
    { 
     List<Pet> pets = 
       new List<Pet>{ new Pet { Name="Barley", Age=8 }, 
          new Pet { Name="Boots", Age=4 } 
          }; 

     var p1 = pets.ReturnPetAgeGreatThan2().ReturnPetAgeGreatThan4(); 

     foreach (var p in p1) 
     { 
      // Removed it to keep it simple 
      //Console.WriteLine("Pet Name:{0},Age:{1}", p.Name, p.Age); 
     } 

     Console.ReadLine(); 

    } 

    public static IEnumerable<Pet> ReturnPetAgeGreatThan2(this IEnumerable<Pet> p) 
    { 
     Console.WriteLine("I am in ReturnPetAgeGreatThan2"); 

     foreach (var par in p) 
     { 
      if (par.Age > 2) 
       yield return par; 
     } 
    } 

    public static IEnumerable<Pet> ReturnPetAgeGreatThan4(this IEnumerable<Pet> p) 
    { 
     Console.WriteLine("I am in ReturnPetAgeGreatThan4"); 

     foreach (var par in p) 
     { 
      if (par.Age > 4) 
       yield return par; 
     } 
    } 
} 

OutPut

I am in ReturnPetAgeGreatThen4 
    I am in ReturnPetAgeGreatThen2 

Aber sobald ich yield return entfernen und die Funktion ändern, nur verwenden return.The Methoden in Reihenfolge aufgerufen werden.

public static IEnumerable<Pet> ReturnPetAgeGreatThan2(this IEnumerable<Pet> p) 
    { 
     Console.WriteLine("I am in ReturnPetAgeGreatThen2"); 
     var result = p.Where(x => x.Age > 2); 

     return result; 
    } 

    public static IEnumerable<Pet> ReturnPetAgeGreatThan4(this IEnumerable<Pet> p) 
    { 
     Console.WriteLine("I am in ReturnPetAgeGreatThen4"); 
     var result = p.Where(x => x.Age > 4); 
     return result; 
    } 

Ausgabe

 I am in ReturnPetAgeGreatThen2 
    I am in ReturnPetAgeGreatThen4 

Jede Hilfe, dies zu verstehen wird sehr geschätzt.

Antwort

3

Mit yield return erstellen Sie eine implizite Aufzählung. Der Compiler führt in diesem Fall tatsächlich eine Menge Codetransformation durch. Der Hauptpunkt hier ist, dass der Zustand Ihrer Methode gespeichert wird, wann immer ein Wert zurückgegeben wird.

Also, was hier passiert, ist im Grunde, dass Ihre erste Methode gibt ein IEnumerablesofort, wenn sie aufgerufen, aber der Code, der Wert für das erzeugt wird noch nicht ausgeführt. Das passiert nur, wenn es aufgezählt wird. Diese Aufzählung geschieht in Ihrer zweiten Methode, die foreach verwendet. Sie sehen also zuerst die Ausgabe der zweiten Methode, da die Ausgabe der ersten Methode nur dann erfolgt, wenn der erste Wert aus dem Enumerable generiert wird.

In Ihrem zweiten Fall zählen Sie eigentlich nichts auf, sondern geben IEnumerable s zurück, die Werte nur bei Aufzählung generieren/filtern. Da Ihr Methodenkörper jedoch yield return nicht mehr enthält, wird er vom Compiler nicht mehr in und IEnumerable umgeschrieben, was Werte erzeugt. Dies ist also nur eine normale Methode und läuft sofort und in der von Ihnen erwarteten Reihenfolge.

Verwandte Themen