关于语法:C# – 是否为foreach循环的每次迭代调用函数?

C# - Does function get called for each iteration of a foreach loop?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
How does foreach work when looping through function results?

如果我有如下的功能,那么对于for each循环中的每个迭代都会调用returnParts(),还是只调用一次?

1
2
3
4
5
6
7
8
9
10
11
12
private void PrintParts()
{
     foreach(string part in ReturnParts())
     {
         // Do Something or other.
     }
}

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


它只会被调用一次。

P.S.多次打电话也没什么意义。如果您希望每次的结果都不同,那么每次都会重新调用它。你将如何迭代一个不断变化的集合?


您可以通过在函数"returnparts"上放置一个断点来自己确定这一点。如果每次迭代的命中次数都是多个,那么是的。


它只会被调用一次。

foreach循环等效于以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
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();
}

在想for、foreach、while和goto之间的区别时,几周前我写了这个测试代码。在调试模式下,所有的方法都将编译成相同的IL(foreach版本上的变量名除外)。一些nop语句将位于不同的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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、'goto'和foreach。现在,for each语句将使用数组的索引器。对象数组和字符串以类似的方式展开。对象将删除方法调用console.writeline之前发生的装箱,字符串将分别用char itemstring copy...替换T itemT[] copy...。请注意,关键部分不再需要,因为不再使用一次性枚举器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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;
}