为什么 GetEnumerator() 存储在与 IEnumerator 不同的接口中?
-
22-09-2019 - |
题
我想知道为什么 GetEnumerator() 方法从 IEnumerator 中分离出来并放置在 IEnumerable 中。在我看来,将所有枚举器方法保留在 IEnumerator 中会更有意义。
谢谢,
斯科特
解决方案
问问自己, “想象一下,如果这是真的。”
如果所有的枚举方法是一个单一的界面上,怎么可能两个呼叫者在同一时间枚举同一个列表?
有两个接口,因为一个人说,“你可以列举了我”,而另一个人说,“这是一个跟踪给定的枚举任务的对象。”
在IEnumerable
接口是一个工厂,创建只要你想尽可能多的IEnumerator
对象。如何以及何时这些普查员习惯,就是坚持以消费者。
其他提示
IEnumerable
意味着该对象是一个集合或可以以线性方式被遍历数据的源。 IEnumerator
是用于实际执行其执行迭代的接口。
由于“IEnumerable的”说:“来,我历数”(然后你说 - 怎么样,给我枚举),但是“IEnumerator的”说:“我可以枚举您的收藏!”你已经拥有了它,你就不需要得到任何更多。
您得到了很好的答案在这里。只是有些偏重。一个枚举保持状态时,它会跟踪集合中的当前对象的被列举。可通过IEnumerator.Current。而且它知道如何改变这种状态,IEnumerator.MoveNext()。保持状态,需要一个独立的对象存储状态。该状态不能被存储在集合对象内部容易因为只有一个收集对象,但可以有多于一个的枚举器。
我用“轻松”一词,因为它实际上是可能的收集跟踪它的统计员。毕竟,这是返回的迭代器集合类的GetEnumerator()方法的调用。有一个在.NET框架,这样做,Microsoft.VisualBasic.Collection一个集合类。它需要实现一个VB6合同的集合类和合同中明确规定变更集合被枚举它是合法的。这意味着当该集合被修改,它需要一些合理与所有所创建的迭代器对象。
他们想出了一个相当不错的伎俩,WeakReference的可能是受此启发。一看,看在由反射显示的代码。鼓舞人心的东西。挖掘更多一些,并在集合类找到“版本”。真棒特技。
由于经常做列举的是仅沿切向(如果有的话)相关的被列举的事情。如果IEnumerable和IEnumerator的是一样的界面,他们不能被共享,或者你需要有一定的GetEnumerator无类型的参数,允许你在对象传递给枚举。分裂他们允许枚举基础设施,以在不同类型的被潜在共享。
阅读 Bart De Smet 的帖子后 敏林克 我不再相信严格要求拆分两个接口。
例如 - 在上面的链接中,IEnumerable/IEnumerator 被折叠为单个方法接口
Func<Func<Option<T>>>
以及一些基本的实现
public static class FEnumerable
{
public static Func<Func<Option<T>>> Empty<T>()
{
return () => () => new Option<T>.None();
}
public static Func<Func<Option<T>>> Return<T>(T value)
{
return () =>
{
int i = 0;
return () =>
i++ == 0
? (Option<T>)new Option<T>.Some(value)
: (Option<T>)new Option<T>.None();
};
}
...
}
public static Func<Func<Option<T>>> Where<T>(this Func<Func<Option<T>>> source, Func<T, bool> filter)
{
return source.Bind(t => filter(t) ? FEnumerable.Return(t) : FEnumerable.Empty<T>());
}