为什么迭代器在异常上的行为不同于LINQ可枚举?

问题描述 投票:1回答:1

[我正在研究iterator方法的内部机制,并且我注意到通过迭代器获得的IEnumerator<T>与通过LINQ方法获得的IEnumerator<T>在行为上存在奇怪的区别。如果枚举期间发生异常,则:

  1. LINQ枚举器保持活动状态。它跳过一个项目,但继续生产更多。
  2. 迭代器枚举器完成。它不再生产任何物品。

示例。 IEnumerator<T>会被顽固地枚举,直到完成:

IEnumerator<int>

让我们尝试枚举在第三个项目上抛出的LINQ枚举器:

private static void StubbornEnumeration(IEnumerator<int> enumerator)
{
    using (enumerator)
    {
        while (true)
        {
            try
            {
                while (enumerator.MoveNext())
                {
                    Console.WriteLine(enumerator.Current);
                }
                Console.WriteLine("Finished");
                return;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception: {ex.Message}");
            }
        }
    }
}

输出:

12例外:糟糕!45例外:糟糕!78例外:糟糕!10完成

现在让我们对在第三个项目上抛出的迭代器进行相同的尝试:

var linqEnumerable = Enumerable.Range(1, 10).Select(i =>
{
    if (i % 3 == 0) throw new Exception("Oops!");
    return i;
});
StubbornEnumeration(linqEnumerable.GetEnumerator());

输出:

12例外:糟糕!完成

我的问题是:这种不一致的原因是什么?哪种行为对实际应用更有用?

注:此观察是在另一个与迭代器相关的问题中的StubbornEnumeration(MyIterator().GetEnumerator()); static IEnumerable<int> MyIterator() { for (int i = 1; i <= 10; i++) { if (i % 3 == 0) throw new Exception("Oops!"); yield return i; } } 之后进行的。


更新:我做了一些观察。并非所有LINQ方法的行为都相同。例如,answer by Dennis1679方法在内部作为.NET Framework上的Take实现,因此它的行为就像一个迭代器(异常立即完成)。但是在.NET Core上,它的实现方式可能有所不同,因为在例外情况下,它会继续运行。

c# linq iterator enumeration
1个回答
0
投票
© www.soinside.com 2019 - 2024. All rights reserved.