【问题标题】:Why doesn't .NET have a bidirectional enumerator?为什么.NET 没有双向枚举器?
【发布时间】:2010-12-08 10:52:23
【问题描述】:

在 SO 上已多次询问如何实现双向枚举器(herehere)。我的问题不是如何(这对大多数情况来说都是微不足道的),而是为什么在.NET平台中不存在这种类型。

public interface IBidirectionalEnumerator<T> : IEnumerator<T>
{
    bool MovePrev();
}

显然,有许多集合类型无法实现这一点,因为MoveNext() 具有破坏性或会更改底层集合的状态。但相反,许多类型可以轻松实现这一点(ListIListLinkedListarray)。

为什么不存在这种类型?

【问题讨论】:

  • 如果枚举它会改变它的状态,那么你的集合设计就有很大的问题。
  • 同意。但是确实有一些集合在枚举时应该改变,比如堆栈或队列。
  • 除非您使用 IEnumerable 包裹在流式传输类型或系统资源(如 StreamReader 或文件列表)上。
  • 另外,虽然所有集合都是枚举,但并非所有枚举都是集合。
  • 同意马修,我的评论太短视了。副作用确实没问题(流确实是一个很好的例子,查询是另一个例子),但它们必须本地化。我认为多次枚举某些东西,即使在枚举器之间来回切换,也应该是一致的。否则你会做非常不直观的事情。

标签: c# .net ienumerator enumerators


【解决方案1】:

当您设计一个框架时,您必须决定在不同的抽象级别上做些什么。权衡是,如果您选择在高抽象级别公开事物,您将以失去对事物的细粒度控制为代价实现泛化。如果您选择在较低抽象级别公开内容,您的概念也无法概括,但您可以控制较低级别的细节。

这是一个设计决定。实现这两者的成本很高,并且会使框架更加臃肿,并且在添加功能时需要同时支持这两者。您将来需要保持向后兼容性。将您能想到的所有内容都添加到 BCL 中而不确保它具有显着的好处,这不是明智之举。

【讨论】:

    【解决方案2】:
    • IEnumerator 支持 c# foreach 语句以及其他语言的循环构造。
    • IBidirectionalEnumerator 不支持任何语句或通用编程习惯。

    【讨论】:

    • 这并不完全正确。 C# 只需要MoveNext 方法和Current 属性即可工作。它完全不依赖于接口。
    • 其实IEnumerator&lt;T&gt; 不需要foreach。只要你的类有一个不带参数的方法GetEnumerator() 并返回一个具有object Current { get; } 属性和void MoveNext() 方法的对象,那么foreach 就可以很好地使用它。
    • 格雷格:真的吗?!那么 IEnumerator 是有效的鸭子类型吗?这是一个启示。
    • 不是鸭式的。 C# 只需检查类型是否实现接口或是否具有所需的方法/属性。为 foreach 循环生成的 IL 不会在任何地方使用 IEnumerable,因此无需鸭式。
    • 这就是我所说的鸭式打字的意思。这是编译时的鸭子类型,没错,但它仍然像鸭子一样嘎嘎叫。
    【解决方案3】:

    因为要么没有人想到它,要么没有人认为它会特别有用,或者因为没有足够的预算或......

    这不是真的必要,是吗?您可以轻松地自己实现它。也许 BCL 团队认为实施、测试、记录等痛苦不值得。永远不要低估功能的成本,这听起来“容易”,但确实有成本。

    特别是因为没有人实现的单个接口看起来很奇怪,不是吗?你会期望 List、Array 等实现接口,这最终是相当多的工作。

    【讨论】:

    • 正如 Raymond Chen 所说,所有功能都以 -100 分开始。
    【解决方案4】:

    显然,有许多集合类型无法实现这一点,因为MoveNext() 具有破坏性或会改变底层集合的状态。

    MoveNext() 是非破坏性的。实际上,如果在创建IEnumerator 和调用MoveNext() 之间更改了底层集合的状态,则对MoveNext() 的调用将失败。

    IEnumerator 的目的是遍历集合中的所有项目一次,如果集合具有本地顺序,则按照集合的本地顺序。 IEnumerator 并非旨在用作集合导航设备,就像在 C++ 中可能发现的那样。

    【讨论】:

    • 那么 C# 集合导航设备会是什么?我的意思是 C# 版本的 C++ 迭代器?
    【解决方案5】:

    另外,这样做的动机是什么? “向后”迭代的语言支持?

    迭代器模式对一组元素的“方向性”概念没有给予太多重视。这是一个简单的模式,用于提供一个简单的接口来迭代一个集合。

    【讨论】:

      【解决方案6】:

      一个更大的问题是为什么 .Net 没有实现 IReadableByIndex,而 IReadableByIndex 又会被 IList 继承。这种类型不会增加产生读写 IList 实现所需的工作,并且会减少产生只读实现(将实现 IReadableByIndex,而不是 IList)所需的工作。

      但是,思考这样的“为什么”并没有太大用处。 .Net 就是这样。解决 .Net 5.0 情况的唯一方法是允许声明实现读写属性的接口可以被视为隐式实现只读版本(以便允许 IList 继承协变IReadableByIndex 无需添加显式 Get 方法)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-07
        • 2019-06-21
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        相关资源
        最近更新 更多