【问题标题】:IEnumerable IEnumerator with and without Current moveNext resetIEnumerable IEnumerator 带和不带 Current moveNext 重置
【发布时间】:2014-09-05 20:53:09
【问题描述】:

我试图了解 IEnumerable 接口的工作原理,但发现很难理解这个概念,因为一些示例使用 IEnumerator、GetEnumerator、Current、moveNext、Reset,而一些示例演示了 IEnumerable 与 IEnumerator 没有 Current、moveNext、Reset 与嵌套内部班级。

我需要一个简单的例子来理解这个概念,以及何时适合将 IEnumerator 与 Current、moveNext、Reset 一起使用,何时不适合。

【问题讨论】:

  • 消费?还是实施?
  • @MarcGravell。如果您能从这两个角度提供解释,我将不胜感激。谢谢
  • @MarcGravell。使用 .NET 4.5 我通常不需要实现 IEnumerator 对吗?
  • 它实际上不是 .NET 运行时功能;它是一个编译器特性; IIRC,迭代器块自 C# 2.0 以来一直存在,而 .NET 4.5 附带的编译器版本比这要高得多,所以:是的
  • @MarcGravell。我们什么时候真的需要使用 IEnumerable?

标签: c# .net collections ienumerable ienumerator


【解决方案1】:

几乎从不适合使用Reset(),因为该方法明显不可靠:例如,迭代器块不支持它。因此,不必担心实施它。

如果您的意思是实现它:大多数时候,最合适的做法是使用迭代器块(又名yield return),因为手动执行此操作很困难,容易出错,而且通常没有什么大用处。您需要有一些非常具体的想法才能保证手动实现枚举器。

你看到的一些例子可能在迭代器块被添加到语言之前;在这种情况下,他们别无选择除了手动编写迭代器。

大多数时候:让编译器担心繁重的工作。 yield return 是你的朋友。注意:List<T> 之类的东西使用值类型的自定义迭代器等来最小化影响;请注意,当您在 List<T> 上使用 foreach 时,您甚至没有真正使用 IEnumerable<T> - 您只是在使用原始的 GetEnumerator() 和相关的 API。 foreach 可以使用 IEnumerable<T>,但它并不需要它。

【讨论】:

    【解决方案2】:

    提供者 ========

    这是一个我将类与枚举器分开的示例。 MyEnumerableClass 是 Enumerable,因此如果有人需要枚举它,它可以检索该类的枚举器。

    using System;
    using System.Collections;
    
    
    class MyEnumerableClass : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            return new MyEnumerableClassEnumerator();
        }
    }
    

    枚举器负责枚举类上的元素。 在这个例子中,我没有这样做,我希望这种方式更清楚。 在此示例中,类 MyEnumerableClass 和该类上的枚举器 (MyEnumerableClassEnumerator) 不相关。通常枚举器会枚举类中包含的某些内容,因此枚举器会保留对类的引用。此外,如果类的状态发生“显着”变化,则枚举器无法枚举它,因此它应该引发 InvalidOperationException。这种行为通常是通过在类中添加版本标识符(即 int versionId)来实现的。当枚举器被实例化时,它会保存 versionId。如果在 MoveNext 调用中枚举器发现 versionId 已更改,则会引发异常。 通过这种方式,您可以同时在同一个类上激活多个枚举器。 无论如何,这里是一个非常简单的枚举器示例

    class MyEnumerableClassEnumerator : IEnumerator
    {
        int myStatusVariable = 0;
    
        public object Current
        {
            get { return myStatusVariable; }
        }
    
        public bool MoveNext()
        {
            return ++myStatusVariable < 10;
        }
    
        public void Reset()
        {
            myStatusVariable = 0;
        }
    }
    

    消费者 ======== 现在是消费者。 您可以通过 2 种方式使用枚举器,通过语言(生成接口调用)或自己生成调用

    这里是基于上述类的示例

            MyEnumerableClass myEnumerableClass = new MyEnumerableClass();
    
            foreach (var item in myEnumerableClass)
            {
                Console.WriteLine(item);
            }
    
    
            IEnumerator enumerator = myEnumerableClass.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Console.WriteLine(enumerator.Current);
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 2011-11-04
      • 2012-07-13
      • 1970-01-01
      • 2012-04-01
      相关资源
      最近更新 更多