2010-04-16 56 views
5

我在使用中,我使用yield return這是行不通的方法有點麻煩的時候不叫......方法採用收益率回報

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

上面的代碼運行永遠,如果調用的是對此方法作出了簡單的改變。

但是如果我改變...

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; 
} 

它工作得很好。

我不明白爲什麼第一種方法永遠不會運行,你能幫我理解這裏發生的事情嗎?

+0

你怎麼稱呼這個方法? – gammelgul 2010-04-16 11:56:20

+0

調用像這樣的構造函數:'Prop = SomeMethod(param);' – DaveParsons 2010-04-16 11:57:33

回答

7

當調用者實際開始枚舉返回的集合時,「yield」版本僅爲「運行」。

如果,例如,你只能得到集合:

var results = SomeObject.SomeMethod (5); 

,不要用它做任何事情時,SomeMethod將不會執行。

只有當您開始枚舉results集合時,它纔會命中。

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

明亮,正是我需要知道的!謝謝 – DaveParsons 2010-04-16 12:11:16

2

yield return方法實際上是轉換成懶洋洋地檢索信息的狀態機類 - 只有當你真正提出要求。這意味着爲了實際拉取數據,您必須遍歷方法的結果。

// Gives you an iterator object that hasn't done anything yet 
IEnumerable<MyClass> list = SomeMethod(); 

// Enumerate over the object 
foreach (var item in list) { 
    // Only here will the data be retrieved. 
    // The method will stop on yield return every time the foreach loops. 
} 

它在第二種情況下運行的原因是因爲沒有收益塊,因此整個方法一次運行。

在這個特定的情況下,你不可能有任何優勢,因爲你的GetClassesFromDb()也不是一個。這意味着它將在第一次運行時同時檢索所有數據。當你可以一次訪問一個項目時,最好使用迭代器塊,因爲如果你不再需要它們,你可以停下來。

0

我不得不以近乎災難的方式學習如何冷靜/危險yield是當我決定讓我們公司的解析器懶洋洋地讀取傳入的數據。幸運的是,我們少數的實現函數中只有一個實際使用了yield關鍵字。花了幾天的時間才意識到它根本沒有做任何工作。

產量關鍵字會因爲懶惰,因爲它可能會,包括跳過的方法完全,如果你不把它與一些工作像.ToList().FirstOrDefault().Any()

下面是兩個變化,一個使用關鍵字和一個返回直接列表。一個人甚至不會去執行,而另一個人即使看起來是一樣的。

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; 
    } 
} 

這個故事告訴我們:確保如果有一個返回IEnumerable的一種方法,你在那個方法使用yield,你有什麼事情會遍歷結果,或方法將根本不執行。