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

C会受益于枚举器的种类之间的区别,比如C++迭代器吗?

  •  5
  • cdiggins  · 技术社区  · 15 年前

    我一直在考虑这个问题 IEnumerator.Reset() 方法我在MSDN文档中读到它仅用于COM互操作。作为C++程序员,它看起来像一个 IEnumerator 支持 Reset 这就是我所说的 forward iterator ,而 迭代器 这不支持 这真是一个 input iterator .

    所以我的问题的第一部分是,这种理解正确吗?

    我问题的第二部分是,如果在输入迭代器和前向迭代器(或者如果您愿意的话是“枚举器”)之间进行区分,那么在C#中会有什么好处?这是否有助于消除程序员之间的一些困惑,如本文中所述 SO question about cloning iterators ?

    编辑:关于前向迭代器和输入迭代器的说明。输入迭代器仅保证只能枚举集合(或从生成器函数或输入流)的成员一次。这正是IEnumerator在C#中的工作方式。是否可以再次枚举,取决于是否 重置 支持。前向迭代器没有此限制。您可以根据需要经常枚举成员。

    一些C#程序员不明白为什么 迭代器 无法在多路径算法中可靠地使用。考虑以下情况:

    void PrintContents(IEnumerator<int> xs)
    {
      while (iter.MoveNext())
        Console.WriteLine(iter.Current); 
      iter.Reset();
      while (iter.MoveNext())
        Console.WriteLine(iter.Current); 
    }
    

    如果我们打电话 PrintContents 在这种情况下,没有问题:

    List<int> ys = new List<int>() { 1, 2, 3 }
    PrintContents(ys.GetEnumerator()); 
    

    但是,请看以下几点:

    IEnumerable<int> GenerateInts() {   
      System.Random rnd = new System.Random();
      for (int i=0; i < 10; ++i)
        yield return Rnd.Next();
    }
    
    PrintContents(GenerateInts());
    

    如果 支持 ,换句话说,支持多通道算法,那么每次迭代集合时都会有所不同。这将是不可取的,因为这将是令人惊讶的行为。这个例子有点假,但它确实发生在现实世界中(例如,从文件流读取)。

    5 回复  |  直到 7 年前
        1
  •  3
  •   Community Egal    7 年前

    Reset 这是一个大错误。我称之为恶作剧 重置 . 在我看来,在.NET类型系统中,反映“前向迭代器”和“输入迭代器”之间区别的正确方法是 IEnumerable<T> IEnumerator<T> .

    this answer 微软的埃里克·利珀特(Eric Lippert)(毫无疑问,我的观点是,他是一个拥有比我所宣称的更多资历的人,这是一个设计错误)在评论中也提出了类似的观点。另见 his awesome blog .

        2
  •  2
  •   jalf    15 年前

    利益

    C++的区别在于其灵活的类型系统。在C#中,没有一种健壮的通用方法来克隆对象,这是表示前向迭代器(支持多过程迭代)所必需的。当然,为了让它真正有用,您还需要支持双向和随机访问迭代器/枚举器。为了让它们都能顺利工作,你需要一些形式的鸭式输入,比如C++模板。

    在C++中,迭代器应该代表一系列值所需的所有知识。给定一对迭代器,我不知道 需要

    在C#中,枚举数并不意味着做那么多。最终,它们只是为了让您以线性方式运行序列而设计的。

    Reset()

    不幸地

        3
  •  1
  •   Matt Brunell    15 年前

    你几乎从不使用 IEnumerator 直接地通常你做一个 foreach 语句,它期望 IEnumerable .

    IEnumerable _myCollection;
    ...
    foreach (var item in _myCollection) { /* Do something */ }
    

    迭代器 任何一个如果要传递需要迭代的集合,则传递 数不清 . 自从 ,它可用于多次迭代集合(多次传递)。

    不需要一个 Reset() 作用于 迭代器

        4
  •  1
  •   supercat    9 年前

    如果有一种方法可以询问一个问题,那么.NET框架将受益匪浅 IEnumerator<T> IEnumerable<T> ,但如果能够询问枚举器的问题,则允许代码从包装器接收枚举器,如 ReadOnlyCollection 以改进的方式使用基础集合,而不必涉及包装器。

    IEnumerable<T> 通过将其全部内容读取到数组,处理并丢弃枚举数,并从数组中获取枚举数(使用该枚举数代替原始放弃的枚举数),将数组包装为 ReadOnlyCollection<T> ,并将其退回。尽管这种方法适用于满足上述标准的任何类型的可枚举集合,但对于大多数集合来说,效率极低。有一种要求枚举数以不可变的形式产生其剩余内容的方法 IEnumerable<T> 将允许多种枚举数更有效地执行指定的操作。

        5
  •  -1
  •   Matt Brunell    15 年前

    我不这么认为。我会打电话 IEnumerable 前向迭代器和输入迭代器。它不允许您后退或修改基础集合。加上 foreach 关键字,迭代器在大多数情况下几乎是一种非思想工具。

    意见: 每一个都要 )与输出迭代器( 对每个人做点什么

    还有 IList<T>