2010-04-16 3 views
5

Ich bin mit einem Verfahren haben Probleme, in denen ich yield return verwende dies nicht funktioniert ...Methode nicht aufgerufen, wenn Ausbeute unter Verwendung Rückkehr

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     yield return new MyClass((int)row["Id"], (string)row["SomeString"]); 
    }  
} 

Der obige Code nie ausgeführt wird, wenn der Anruf Bei dieser Methode geht es nur darüber hinweg.

Allerdings, wenn ich ändern ...

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    IList<MyClass> classes = new List<MyClass>(); 

    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     classes.Add(new MyClass((int)rows["Id"], (string)row["SomeString"]); 
    } 

    return classes; 
} 

Es funktioniert gut.

Ich verstehe nicht, warum das erste Verfahren läuft nie, könnten Sie mir helfen, zu verstehen, was hier geschieht?

+0

Wie nennt man die Methode? – gammelgul

+0

Rufen Sie einen Konstruktor wie folgt auf: 'Prop = SomeMethod (param);' – DaveParsons

Antwort

7

Die „Ausbeute“ Version ist nur „run“, wenn der Anrufer tatsächlich die zurückgegebene Sammlung aufzuzählen beginnt.

Wenn Sie zum Beispiel nur die Sammlung erhalten:

var results = SomeObject.SomeMethod (5); 

und nicht mit ihm nichts tun, wird die SomeMethod nicht ausgeführt werden.

Erst wenn Sie die results Sammlung starten aufzählt, wird es treffen.

foreach (MyClass c in results) 
{ 
    /* Now it strikes */ 
} 
+0

Brilliant, genau was ich wissen musste! Vielen Dank – DaveParsons

2

yield return Methoden sind tatsächlich in den Zustand Maschinenklassen umgewandelt, die Informationen lazily abrufen - nur, wenn Sie tatsächlich danach fragen. Das bedeutet, dass Sie, um Daten tatsächlich zu ziehen, über das Ergebnis Ihrer Methode iterieren müssen.

Der Grund, warum es im zweiten Fall ausgeführt wird, liegt daran, dass es keinen Ertragsblock gibt und somit die gesamte Methode auf einmal ausgeführt wird.

In diesem speziellen Fall ist es unwahrscheinlich, dass Sie einen Iteratorblock gegenüber einem regulären Iteratorblock verwenden können, da auch Ihr GetClassesFromDb() kein Iteratorblock ist. Dies bedeutet, dass beim ersten Ausführen alle Daten gleichzeitig abgerufen werden. Iteratorblöcke werden am besten verwendet, wenn Sie einzeln auf Elemente zugreifen können, da Sie auf diese Weise anhalten können, wenn Sie sie nicht mehr benötigen.

0

Ich musste auf eine fast katastrophale Art und Weise lernen, wie cool/gefährlich yield ist, als ich mich entschloss, den Parser unserer Firma dazu zu bringen, eingehende Daten faul zu lesen. Glücklicherweise hat nur eine Handvoll unserer Implementierungsfunktionen das Schlüsselwort yield verwendet. Ich brauchte ein paar Tage, um zu erkennen, dass es in aller Stille überhaupt keine Arbeit machte.

Die Ausbeute Schlüsselwort wird es so faul sein, wie es nur kann, einschließlich über das Verfahren des Überspringen völlig, wenn Sie es nicht tun setzen, mit etwas Arbeit wie .ToList() oder .FirstOrDefault() oder .Any()

Im Folgenden sind zwei Varianten, eine Verwenden des Schlüsselworts und Eins, die eine direkte Liste zurückgibt. Man wird sich nicht einmal bemühen, etwas auszuführen, während das andere es tun wird, auch wenn sie gleich aussehen.

public class WhatDoesYieldDo 
{ 
    public List<string> YieldTestResults; 

    public List<string> ListTestResults; 

    [TestMethod] 
    public void TestMethod1() 
    { 
     ListTest(); 
     Assert.IsTrue(ListTestResults.Any()); 

     YieldTest(); 
     Assert.IsTrue(YieldTestResults.Any()); 
    } 

    public IEnumerable<string> YieldTest() 
    { 
     YieldTestResults = new List<string>(); 
     for (var i = 0; i < 10; i++) 
     { 
      YieldTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
      yield return i.ToString(CultureInfo.InvariantCulture); 
     } 
    } 

    public IEnumerable<string> ListTest() 
    { 
     ListTestResults = new List<string>(); 

     for (var i = 0; i < 10; i++) 
     { 
      ListTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
     } 

     return ListTestResults; 
    } 
} 

Moral der Geschichte: Stellen Sie sicher, dass, wenn eine Methode, die IEnumerable zurückgibt und Sie yield in dieser Methode, Sie haben etwas, das über die Ergebnisse laufen wird, oder das Verfahren wird überhaupt nicht ausgeführt werden.

Verwandte Themen