2010-05-03 61 views

回答

13

收益實現直到需要時纔會到達代碼。

例如,下面的代碼:

public IEnumerable<int> GetInts() 
{ 
    yield return 1; 
    yield return 2; 
    yield return 3; 
} 

將實際編譯成執行IEnumerable<int>GetInts()身體會返回一個類的實例嵌套類。

使用反射鏡可以看到:

public IEnumerable<int> GetInts() 
{ 
    <GetInts>d__6d d__d = new <GetInts>d__6d(-2); 
    d__d.<>4__this = this; 
    return d__d; 
} 

編輯 - 增加更多的信息關於GetInts實現:
此實現使得懶惰是基於EnumeratorMoveNext()方法的方式。生成可枚舉的嵌套類(示例中的<GetInts>d__6d)時,它具有一個狀態,並且每個狀態都連接一個值(這是一個簡單的例子,在更高級的情況下,代碼到達狀態時將評估該值)。如果我們採取的<GetInts>d__6dMoveNext()代碼一看,我們會看到狀態:

private bool MoveNext() 
{ 
    switch (this.<>1__state) 
    { 
     case 0: 
      this.<>1__state = -1; 
      this.<>2__current = 1; 
      this.<>1__state = 1; 
      return true; 

     case 1: 
      this.<>1__state = -1; 
      this.<>2__current = 2; 
      this.<>1__state = 2; 
      return true; 

     case 2: 
      this.<>1__state = -1; 
      this.<>2__current = 3; 
      this.<>1__state = 3; 
      return true; 

     case 3: 
      this.<>1__state = -1; 
      break; 
    } 
    return false; 
} 

當枚舉被要求爲當前對象返回連接到當前狀態的對象。

爲了表明,只有當它需要你可以看看下面這個例子的代碼進行評估:

[TestFixture] 
public class YieldExample 
{ 
    private int flag = 0; 
    public IEnumerable<int> GetInts() 
    { 
     yield return 1; 
     flag = 1; 
     yield return 2; 
     flag = 2; 
     yield return 3; 
     flag = 3; 
    } 

    [Test] 
    public void Test() 
    { 
     int expectedFlag = 0; 
     foreach (var i in GetInts()) 
     { 
      Assert.That(flag, Is.EqualTo(expectedFlag)); 
      expectedFlag++; 
     } 

     Assert.That(flag, Is.EqualTo(expectedFlag)); 
    } 
} 

我希望這是更清晰一點。我建議使用Reflector來查看代碼,並在更改「yield」代碼時觀察編譯的代碼。

+0

@Elisha:請提供關於GetInts()的更多詳細信息。 – 2010-05-03 10:53:54

+0

@masoud ramezani,增加了關於GetInts嵌套枚舉類的更多信息。 – Elisha 2010-05-03 13:52:38

+0

謝謝你的完整答案。 – 2010-05-03 14:22:36

4

基本上迭代器使用yield語句implementated被編譯成一個實現state machine類。

如果您從不foreach(=迭代並實際使用)返回的IEnumerable<T>,代碼永遠不會實際執行。如果你這樣做,只需要確定下一個返回值所需的最小代碼就可以執行,只有當請求下一個值時才能恢復執行。

當您在調試器中單步執行此類代碼時,您實際上可以看到此行爲發生。至少嘗試一次:我認爲這是一步一步發生的。