2009-12-28 72 views
13

C#的yield關鍵字通過教程工作的(專業ASP.NET MVC書呆子晚餐),我碰到這個代碼片段來yield,但我想我的理解還是有點朦朧。看起來要做的是創建一個對象,允許循環通過集合中的項目,而實際上並不需要循環,除非和直到絕對必要。有趣的使用書呆子晚餐教程

雖然這個例子對我來說有點奇怪。我認爲它的做法是延遲創建任何RuleViolation實例,直到程序員實際使用for each或LINQ擴展方法(如.ElementAt(2))請求集合中的特定項目。

除此之外,雖然,我有一些問題:

  1. 什麼時候該if語句的條件部分得到評估?當調用GetRuleViolations()時,或者當枚舉實際上迭代?換句話說,如果Title的值從null更改爲Really Geeky Dinner到我呼叫GetRuleViolations()的時間與我嘗試實際迭代它的時間之間,是否會創建RuleViolation("Title required", "Title")

  2. 爲什麼需要yield break;?這裏真的在做什麼?

  3. 比方說Title爲空或空白。如果我打電話給GetRuleViolations(),然後遍歷所產生的枚舉兩次,將調用new RuleViolation("Title required", "Title")多少次?

+3

.Net編譯器將這種語法糖變成更混雜的形式。編譯樣本,然後在反射器中加載IL。你應該正確地理解那裏到底發生了什麼。 – 2009-12-28 19:22:14

回答

17

包含yield命令的功能是比正常功能區別對待。調用該函數後面發生的事情是,匿名類型由該函數的特定IEnumerable類型構成,該函數創建該類型的對象並將其返回。每次調用IEnumerable.MoveNext時,匿名類都包含執行函數主體的邏輯,直到下一個yield命令爲止。這有點誤導,函數的主體並不像一個普通的函數那樣在一個批處理中執行,而是以枚舉的形式執行,當枚舉器向前移動一步時,每個部分都會執行。

至於你的問題:

  1. 正如我所說的,每個if得到,當你遍歷到下一個元素執行。
  2. yield break在上例中確實沒有必要。它所做的是終止枚舉。
  3. 每次迭代枚舉時,都會再次強制執行代碼。在相關線上放置一個斷點併爲自己測試。
+0

+1真的很清楚和有用的答案,謝謝。如果你不介意的話,只是一個小問題:你能想到一個例子,其中'yield break'*是必要的嗎? – devuxer 2009-12-28 19:43:01

+1

小的澄清 - 你的意思是'IEnumerator []'在你說'IEnumerable []''的地方。 – 2009-12-28 19:47:18

+0

所以在這個例子中'yield break'是必須的,因爲如果沒有創建'RuleViolation',它會拋出異常,對吧? – Ronald 2009-12-28 19:54:46

6

1)取本簡單的例子:

public void Enumerate() 
{ 
    foreach (var item in EnumerateItems()) 
    { 
     Console.WriteLine(item); 
    } 
} 

public IEnumerable<string> EnumerateItems() 
{ 
    yield return "item1"; 
    yield return "item2"; 
    yield break; 
} 

每次調用從IEnumeratorMoveNext()時間從yield點移動到下一個代碼可執行行代碼返回。

2)yield break;將告訴IEnumerator沒有什麼更多的枚舉。

3)每次枚舉一次。

yield break;使用

public IEnumerable<string> EnumerateUntilEmpty() 
{ 
    foreach (var name in nameList) 
    { 
     if (String.IsNullOrEmpty(name)) yield break; 
     yield return name; 
    }  
} 
+0

確定關於「3)一次」?據我瞭解,這是每次重新評估(見這裏的其他兩個答案)。 – 2009-12-28 19:32:36

+0

我澄清了它。 – ChaosPandion 2009-12-28 19:33:54

+0

如果你列出了一個列表,爲什麼不重複它呢? 'yield'方式可以讓你不顯式地構造一個列表。在你的情況下,例如: public IEnumerable Enumerate() { yield return「item1」; 產量回報「item2」; } – 2009-12-28 19:38:22

2

短版:

1:產率爲神奇「停止,稍後再回來」的關鍵字,所以如果在一個「主動」一個前聲明進行了評估。

2:收率斷裂明確地結束該枚舉(認爲在開關殼體 「中斷」)

3:每當。當然,您可以將結果緩存到列表中,然後迭代。

相關問題