2013-08-01 80 views
2

學習集合和IEnumerable和IEnumerator接口。 我有以下程序。當我踏進使用yield return時GetEnumerator()方法會發生什麼?

IEnumerator<string> name = sample.GetEnumerator(); 

它調用Console.WriteLine("inside getenumerator");

class Program 
    { 
     static void Main(string[] args) 
     { 
      SampleStrings sample = new SampleStrings(); 
      IEnumerator<string> name = sample.GetEnumerator(); 
      foreach (var item in sample) 
      { 
       Console.WriteLine(item); 
      } 
      Console.ReadLine(); 
     } 
    } 
    class SampleStrings : IEnumerable<string> 
    { 
     public IEnumerator<string> GetEnumerator() 
     { 
      Console.WriteLine("inside getenumerator"); 

      return null;//for testing purpose only 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return this.GetEnumerator(); 
     } 
    } 

現在如果我更換的GetEnumerator當同一IEnumerator<string> name = sample.GetEnumerator(); 被稱爲那麼它不會踏進了以下功能。我希望它能夠進入該功能,但不會返回任何內容,因爲我還沒有撥打movenext()。 當我指定讓它以這種方式行事的產量時發生了什麼。該計劃的作品。

public IEnumerator<string> GetEnumerator() 
     { 
      Console.WriteLine("inside getenumerator"); 
      yield return "First"; 
      yield return "Second"; 

     } 
+1

你的「前」代碼不編譯(你不能有'「測試」'從一個函數返回類型的IEnumerator''返回值) – AakashM

+0

@AakashM:更新的代碼。代碼之前只是檢查功能。我沒有真正使用返回值。我的問題清楚了嗎?我知道這有點棘手。 – ckv

回答

6

包含yieldIEnumerator的代碼被轉換爲兩部分。

創建了一個新的IEnumerator類,其中包含您的原始代碼,儘管它已被重寫,因此它可以像您期望的那樣執行。 這是你的原代碼,包括Console.WriteLine的生活。

GetEnumerator()方法包含全新生成的代碼,它只是實例化上面定義的IEnumerator並返回它。

因此,沒有您的代碼在第一個MoveNext()被調用之前運行。

這就是爲什麼你經常會看到下面的模式,例如立即執行參數驗證。該實現分爲兩部分:一個正常方法和一個包含yield的方法。

public IEnumerator<int> GetEnumerator(string whatever) 
{ 
    // Perform validation immediately when called 
    if (whatever == null) throw new ArgumentException(); 
    return GetEnumeratorInternal(whatever); 
} 

private IEnumerator<int> GetEnumeratorInternal(string whatever) 
{ 
    // Everything in this method happens on first MoveNext 
    yield return 1; 
    yield return 2; 
} 
+0

仍在消化答案。理解它的一部分。 – ckv

+0

您可以詳細說明「GetEnumerator()方法包含全新生成的代碼,它們只是實例化上面定義的IEnumerator並將其返回。」聲明。 – ckv

+2

我的意思是:一旦編譯完成,'GetEnumerator()'方法不再與你的任何C#代碼匹配。它包含一些等同於'return new GeneratedEnumeratorClass()'的東西。 _您的生成器代碼已被編譯爲'GeneratedEnumeratorClass.MoveNext()'。這就是爲什麼當你調用一個生成器方法(使用'yield'關鍵字的方法)時,這些代碼都不會執行。它首先在第一個「MoveNext」調用期間執行。 – jods

相關問題