【问题标题】:Working of IEnumerator in c#IEnumerator 在 C# 中的工作
【发布时间】:2017-05-06 13:05:49
【问题描述】:
static void Main()
{
    DaysOfTheWeek days = new DaysOfTheWeek();

    foreach (string day in days)
    {
        Console.Write(day + " ");
    }

    // Output: Sun Mon Tue Wed Thu Fri Sat  
    Console.ReadKey();
}

public class DaysOfTheWeek : IEnumerable
{
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

    public IEnumerator GetEnumerator()
    {
        for (int index = 0; index < days.Length; index++)
        {
            // Yield each day of the week.  
            yield return days[index];
        }
    }
}

在 foreach 循环中发生了什么。它是否调用 GetEnumerator 函数,每次迭代或 foreach 都被 GetEnumerator 函数替换?在这种情况下复杂度会达到 O(n2) 吗?

【问题讨论】:

标签: c# .net ienumerable


【解决方案1】:

yield return 创建一个状态机,该状态机基本上返回一个值,然后等待调用方(您的第一个 foreach)请求枚举器中的下一项。

IEnumerable 只是一个接口,描述了一种对一组数据进行迭代的方法,其中的IEnumerator 是描述如何调用迭代器的接口。

【讨论】:

  • 复杂度好像是O(n2)?不是吗?
  • 不,为什么应该是 O(n2)?只需 O(n) 即可。
  • 列表/数组的枚举器使用一个 int 来指向所请求的元素。对于foreach 中的每个循环,都会调用MoveNext,并且只增加一个指针。在这些结构中查找是 O(1)。参考:referencesource.microsoft.com/#mscorlib/system/collections/…
  • A foreach 遍历所有项目,所以它总是O(n),对吧?
【解决方案2】:

在这篇博文中有一个很好的yield return 描述:

https://www.kenneth-truyers.net/2016/05/12/yield-return-in-c/

基本上是这样说的

foreach 循环的每次迭代都会调用迭代器方法。当到达 yield return 语句时,返回值,并保留代码中的当前位置。下次调用迭代器函数时,将从该位置重新开始执行。

由于为下次调用保留了位置,我认为复杂度应该是 O(n) 而不是 O(n2)。

【讨论】:

    【解决方案3】:

    不,GetEnumerator 不会在每次迭代中被调用。如果您在发布配置中编译代码并检查生成的 IL 代码,您最终会得到这样的代码。

    IEnumerator enumerator2 = days.GetEnumerator();
    try
    {
        while (enumerator2.MoveNext())
        {
            Console.Write((string)enumerator2.Current + " ");
        }
    }
    finally
    {
        IDisposable disposable = enumerator2 as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
    

    所以基本上你可以自己编写相同的代码,foreach 只是帮助你编写更少代码的语法糖。

    【讨论】:

      猜你喜欢
      • 2021-02-06
      • 2022-10-05
      • 1970-01-01
      • 2019-10-27
      • 1970-01-01
      • 2016-08-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-30
      相关资源
      最近更新 更多