C# - 是否为foreach循环的每次迭代调用函数?

时间:2010-03-15 13:47:53

标签: c# syntax

  

可能重复:
  How does foreach work when looping through function results?

如果我具有以下功能 - 将在foreach循环中为每次迭代调用ReturnParts(),还是只调用一次?

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

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

4 个答案:

答案 0 :(得分:30)

它只会被调用一次。

P.S。多次调用它没有多大意义。如果您希望每次结果都不同,您可以每次重新调用它。你会如何迭代不断变化的集合?

答案 1 :(得分:19)

您可以通过在函数“ReturnParts”上放置一个断点来自行确定。如果每次迭代都达到多次,那么肯定是。

答案 2 :(得分: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();
}

答案 3 :(得分:7)

想知道几周前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();
    }
}

Per @ Eric的评论......

我已使用通用数组扩展了forwhile,'goto'和foreach。现在for each语句看起来使用数组的索引器。对象数组和字符串以类似的方式扩展。对象将删除在方法调用Console.WriteLine之前发生的装箱,并且字符串将分别用T itemT[] 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;
}