mck*_*mey 3 c# ienumerable ienumerator design-patterns
我有一个C#类需要IEnumerable<T>在一堆方法中处理一系列items(),所以我不能简单地foreach在一个方法中.我打电话给它.GetEnumerator()并传递它IEnumerator<T>,它很有效,在循环一个序列时给了我所需的灵活性.
现在我想让其他人在这个过程中添加逻辑.最自然的方法是为它们提供一个接受方法的接口IEnumerator<T>.简单,完成,它的工作原理.
但我担心这是一种反模式.他们必须知道IEnumerator<T>已经.MoveNext()调用过,所以他们可以简单地访问.Current.另外,我没有看到IEnumerator<T>在接口中使用的任何先例.
IEnumerator<T>自身?更新:正如我在下面的评论中提到的:我想要的是某种通用Stream<T>.我需要能够有效地看到下一个项目(IEnumerator.Current- > .Peek())并使用它(IEnumerator<T>.MoveNext()- > .Pop()).
我用过,IEnumerator<T>因为它明智地符合法案界面.我喜欢在适合时使用常见的BCL类型,但似乎我在滥用这个类型.
所以问题3)是否有适合这种需要的课程?或者我应该创建自己的流,懒惰地执行IEnumerator<T>内部?然后它将被完全封装.我不想使用许多现有的集合,因为它们有内部存储,而我希望存储是IEnumerable<T>iteslf.
好吧,这听起来像是共识是这样做,IEnumerator<T>往往是一个ValueType以及不知道先验状态,IEnumerator<T>通常是一个坏主意传递它.
我听过的最好的建议是创建我自己的类,它会被传递.还有其他建议吗?
你绝对不应该IEnumerator<T>四处传球.除了其他任何东西,它在某些情况下可能会产生一些非常奇怪的效果.例如,你期望在这里发生什么?
using System;
using System.Collections.Generic;
class Test
{
static void ShowCurrentAndNext(IEnumerator<int> iterator)
{
Console.WriteLine("ShowCurrentAndNext");
Console.WriteLine(iterator.Current);
iterator.MoveNext(); // Let's assume it returns true
Console.WriteLine(iterator.Current);
}
static void Main()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
using (var iterator = list.GetEnumerator())
{
iterator.MoveNext(); // Get things going
ShowCurrentAndNext(iterator);
ShowCurrentAndNext(iterator);
ShowCurrentAndNext(iterator);
}
}
}
Run Code Online (Sandbox Code Playgroud)
尝试以下几项更改:
using (List<int>.Enumerator iterator = list.GetEnumerator())
Run Code Online (Sandbox Code Playgroud)
和
using (IEnumerator<int> iterator = list.GetEnumerator())
Run Code Online (Sandbox Code Playgroud)
尝试预测每种情况下的结果:)
现在不可否认,这是一个特别邪恶的例子,但它确实展示了一些与传递可变状态相关的极端案例.我强烈建议您在"中心"方法中执行所有迭代,该方法仅使用当前值调用适当的其他方法.