代码之家  ›  专栏  ›  技术社区  ›  JohnC

Enumerable中的空枚举。选择;或者为什么它的统计员的行为似乎与其他统计员不同?

  •  1
  • JohnC  · 技术社区  · 7 月前

    我正在编写一个库函数,将枚举拆分为多个枚举跨度,但linq Select子句中的枚举器遇到了一个无法解释的问题。请参阅下面的代表性代码示例和输出。

    这个 闻起来像 一个结构枚举器问题,但我永远无法确定问题所在,从而解决它。

    非常感谢您的帮助!

    class Program
    {
        private static IEnumerable<IEnumerable<T>> wrap<T>(IEnumerable<T> collection)
        {
            return wrapped();
    
            IEnumerable<IEnumerable<T>> wrapped()
            {
                Console.Write($"{collection.Count()} items: ");
                using (var etor = collection.GetEnumerator())
                {
                    if (!(etor is object)) throw new Exception();
                    yield return inner();
    
                    IEnumerable<T> inner() { while (etor.MoveNext()) yield return etor.Current; }
                }
            }
        }
    
        static void Main(string[] args)
        {
            var c1 = Enumerable.Range(0, 5);
            var c2 = Enumerable.Range(0, 5).Select(x => x);
            var c3 = Enumerable.Range(0, 5).Select(x => x).ToList();
    
            print(wrap(c1).First()); // ok
            print(wrap(c2).First()); // empty!
            print(wrap(c3).First()); // ok
            Console.WriteLine("<done>"); Console.ReadKey();
    
            void print<T>(IEnumerable<T> tt) => Console.Write(string.Join(", ", tt) + "\n");
        }
    }
    

    控制台输出:

    5 items: 0, 1, 2, 3, 4
    5 items:
    5 items: 0, 1, 2, 3, 4
    <done>
    
    1 回复  |  直到 7 月前
        1
  •  0
  •   Theodor Zoulias    7 月前

    问题是由 using 声明:

    IEnumerable<IEnumerable<T>> wrapped()
    {
        using (var etor = collection.GetEnumerator())
        {
            yield return inner();
    
            IEnumerable<T> inner()
            {
                while (etor.MoveNext()) yield return etor.Current;
            }
        }
    }
    

    枚举数在生成后立即被处理 inner() 枚举,因此内部迭代器试图枚举一个已处理的枚举器。并非所有枚举器在处理时的行为都相同。显然 List<T> 不受处置的影响,而 Select 做。

    推荐文章