2010-03-15 88 views
18

可能重複:
How does foreach work when looping through function results?C# - 是否函數調用每個foreach循環迭代?

如果我有像下面的功能 - 將ReturnParts()被調用在foreach循環每次迭代中,還是會得到公正稱爲一次?

private void PrintParts() 
{ 
    foreach(string part in ReturnParts()) 
    { 
     // Do Something or other. 
    } 
} 

private string[] ReturnParts() 
{ 
    // Build up and return an array. 
} 
+1

重複:http://stackoverflow.com/questions/1632810/how-does-foreach-work-when-looping-through-function-results – 2010-03-15 13:51:04

回答

25

它只會被調用一次。

P.S.多次調用是沒有意義的。如果您希望每次結果都不相同,您可以每次重新調用一次。你將如何迭代不斷變化的集合?

9

它只會被調用一次。

The foreach loop is equivalent to the following code:

IEnumerable<string> enumerator = (collection).GetEnumerator(); 
try { 
    while (enumerator.MoveNext()) { 
     string part = (string)enumerator.Current; 

     // Do Something or other. 

    } 
} finally { 
    IDisposable disposable = enumerator as System.IDisposable; 
    if (disposable != null) disposable.Dispose(); 
} 
17

你可以通過把一個斷點功能「ReturnParts」如果是打複式次,每次迭代然後是它確定這個自己。

+0

感謝您的建議。這是找出自己問題的答案的好方法 – 2016-08-26 06:35:36

6

想知道幾周前for,foreach,while和goto之間的區別,所以我寫了這個測試代碼。所有的方法都會編譯成相同的IL(除了foreach版本的變量名)。在調試模式下,一些NOP語句將處於不同的位置。

static void @for<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     for (; e.MoveNext();) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @foreach<T>(IEnumerable<T> input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     while (e.MoveNext()) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @goto<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
} 
static void @gotoTry<T>(IEnumerable<T> input) 
{ 
    T item; 
    var e = input.GetEnumerator(); 
    try 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
    finally 
    { 
     if (e != null) 
      e.Dispose(); 
    } 
} 

每@ Eric的評論...

我已經擴大forwhile, '轉到' 和foreach與通用陣列。現在for each語句看起來使用數組的索引器。對象數組和字符串以類似的方式展開。對象將刪除方法調用Console.WriteLine和字符串之前發生的拳擊分別將和T[] copy...分別替換爲char itemstring copy...。請注意,關鍵部分不再需要,因爲不再使用一次性枚舉器。

static void @for<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    for (int i = 0; i < copy.Length; i++) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
    } 
} 
static void @foreach<T>(T[] input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    while (i < copy.Length) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
     i++; 
    } 
} 
static void @goto<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    goto check; 
top: 
    item = copy[i]; 
    Console.WriteLine(item); 
    i++; 
check: 
    if (i < copy.Length) 
     goto top; 
} 
+0

@gotoTry是我能想到的最大擴展版本,無需顯示編譯的IL。 – 2010-03-15 14:06:41

+2

很好地完成。當然,這只是用於實現IEnumerable 的擴展。 foreach爲數組和字符串生成不同的代碼。 – 2010-03-15 14:22:21

+0

@Eric:感謝您的反饋。我正在尋求最通用的版本,但我可能會在稍後進一步擴展。 (我主要對goto版本感興趣,大多數人仍然認爲它是「邪惡的」。) – 2010-03-15 14:44:07

相關問題