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

cdi*_*ins 5 c# c++ ienumerable iterator

我一直在想这个IEnumerator.Reset()方法.我在MSDN文档中读到它只适用于COM互操作.作为一个C++程序员,它看起来像我IEnumerator支持的Reset是我称之为前向迭代器,IEnumerator而不支持Reset的实际上是一个输入迭代器.

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

我的问题的第二部分是,如果在输入迭代器和前向迭代器(或者如果你愿意的话,"枚举器")之间有区别,那么在C#中是否有任何好处?它是否有助于消除程序员之间的一些混淆,比如在这个关于克隆迭代器的SO问题中找到的那个?

编辑:前向和输入迭代器的澄清.输入迭代器仅保证您只能枚举集合(或生成器函数或输入流)的成员一次.这正是IEnumerator在C#中的工作方式.您是否可以第二次枚举,取决于是否Reset支持.一个前向迭代器,没有这个限制.您可以根据需要随时枚举成员.

一些C#程序员不会感到不安,以及为什么IEnumerator无法在多通道算法中可靠地使用它.考虑以下情况:

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

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

List<int> ys = new List<int>() { 1, 2, 3 }
PrintContents(ys.GetEnumerator()); 
Run Code Online (Sandbox Code Playgroud)

但请看以下内容:

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

PrintContents(GenerateInts());
Run Code Online (Sandbox Code Playgroud)

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

jal*_*alf 2

有趣的问题。我的看法是,C# 当然会受益。然而,添加并不容易。

C++ 中存在这种区别是因为它的类型系统更加灵活。在 C# 中,您没有强大的通用方法来克隆对象,而这是表示前向迭代器(以支持多遍迭代)所必需的。当然,要使其真正有用,您还需要支持双向和随机访问迭代器/枚举器。为了让它们顺利工作,您确实需要某种形式的鸭子类型,就像 C++ 模板那样。

最终,这两个概念的范围是不同的。

在 C++ 中,迭代器应该表示您需要了解的有关一系列值的所有信息。给定一对迭代器,我不需要原始容器。我可以排序、搜索、操作和复制元素,只要我喜欢。原来的容器不在图片中。

在 C# 中,枚举器的作用并不那么大。最终,它们的设计目的只是让您以线性方式运行该序列。

至于Reset(),人们普遍认为一开始添加它就是一个错误。如果它有效并且正确实现,那么是的,您可以说您的枚举器类似于前向迭代器,但一般来说,最好将其视为错误而忽略。然后所有枚举器仅与输入迭代器相似。

很遗憾。