我一直在考虑IEnumerator.Reset()方法。我在MSDN文档中读到它只适用于COM互操作。作为一名C ++程序员,它看起来像一个IEnumerator支持Reset,我称之为转发迭代器,而不支持PrintContents的<=>实际上是输入迭代器

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

我的问题的第二部分是,如果在输入迭代器和前向迭代器之间有区别(或者如果你愿意,那么<!>“;枚举器<!>;),它会对C#有什么好处吗?它是否有助于消除程序员之间的一些混淆,比如关于克隆迭代器的问题

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

有些C#程序员并不感到不安,为什么<=>无法在多遍算法中可靠地使用。考虑以下情况:

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

如果我们在此上下文中调用<=>,则没问题:

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());

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

有帮助吗?

解决方案

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

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

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

在C ++中,迭代器应该代表您需要了解的一系列值的所有内容。给定一对迭代器,我不需要原始容器。我可以排序,我可以搜索,我可以随意操作和复制元素。原始容器不在图片中。

在C#中,调查员并不意味着做得那么多。最终,它们只是为了让您以线性方式完成序列。

至于Reset(),人们普遍认为首先添加它是错误的。如果它已经工作,并且已经正确实现,那么是的,你可以说你的枚举器类似于前向迭代器,但总的来说,最好忽略它作为一个错误。然后所有枚举器只与输入迭代器类似。

不幸的是

其他提示

Reset是一个很大的错误。我打电话给恶作剧IEnumerable<T>。在我看来,正确的方式来反映你在<!> quot; forward iterators <!>之间的区别。和<!>“输入迭代器<!>”;在.NET类型系统中区分IEnumerator<T>和<=>。

另见这答案,微软的Eric Lippert(在非官方的能力,毫无疑问,我的观点仅仅是他是一个拥有更多凭据而不是声称这是设计错误的人)在评论中提出了类似的观点。另请参阅他精彩的博客

来自C#观点:

您几乎不会直接使用IEnumerator。通常你会做一个foreach语句,它需要一个IEnumerable

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

你也不会传递Reset()。如果要传递需要迭代的集合,则传递<=>。由于<=>有一个函数,它返回一个<=>,它可以用来多次迭代集合(多次传递)。

不需要在<=>上使用<=>功能,因为如果你想重新开始,你只需扔掉旧的(垃圾收集)并获得一个新的。

如果有一种方法可以询问IEnumerator<T>关于它可以支持哪些能力以及它可以做出什么样的承诺,那么.NET框架将会受益匪浅。这些功能在IEnumerable<T>中也会有所帮助,但是能够询问枚举器的问题将允许可以从ReadOnlyCollection等包装器接收枚举器的代码以改进方式使用底层集合,而不必涉及包装器。

给定一个能够完整枚举的集合的枚举器并且不会太大,可以从中生成ReadOnlyCollection<T>,它总是产生相同的项目序列(特别是剩余的项目集合)在枚举器中)通过将其全部内容读取到数组,处理和丢弃枚举器,并从数组中获取枚举器(使用它代替原始的废弃枚举器),将数组包装在<=>中,然后返回。虽然这种方法适用于符合上述标准的任何类型的可枚举集合,但对于大多数集合而言,它的效率可能非常低。有一种方法要求一个枚举器在一个不可变的<=>中产生剩余的内容,这将允许多种类型的枚举器更有效地执行指示的动作。

我不这么认为。我会调用IEnumerable一个前向迭代器和一个输入迭代器。它不允许您向后或修改底层集合。通过添加foreach关键字,迭代器几乎在大多数时候都没有被考虑过。

观点: 输入迭代器(获取每个)与输出迭代器(对每个执行某些操作)之间的区别太小,无法证明对框架的添加是正确的。此外,为了执行输出迭代器,您需要将委托传递给迭代器。对于C#程序员来说,输入迭代器似乎更自然。

如果程序员想要随机访问,还有IList<T>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top