我有一个C#类需要在一堆方法中处理一系列项目(IEnumerable<T>
),所以我不能简单地在方法中foreach
。我打电话给.GetEnumerator()
并传递这个IEnumerator<T>
并且它很有效,在循环一个序列的过程中为我提供了所需的灵活性。
现在我想让其他人在这个过程中添加逻辑。最自然的方法是为他们提供一个接受IEnumerator<T>
的方法的接口。简单,完成,并且有效。
但我担心这是反模式。他们必须知道IEnumerator<T>
已经调用.MoveNext()
,因此他们只需访问.Current
即可。另外,我没有看到在要实现的接口中使用IEnumerator<T>
的任何先例。
IEnumerator<T>
本身? 更新:正如我在下面的评论中提到的:我想要的是某种通用Stream<T>
。我需要能够有效地查看下一个项目(IEnumerator.Current
- &gt; .Peek()
)并使用它(IEnumerator<T>.MoveNext()
- &gt; .Pop()
)。
我使用了IEnumerator<T>
,因为它明智地适合了账单界面。我喜欢在适合时使用常见的BCL类型,但似乎我在滥用这个类型。
问题3)是否有适合这种需要的课程?或者我应该创建自己的Stream,它内部懒惰地执行IEnumerator<T>
?然后它将被完全封装。我不想使用许多现有的集合,因为它们有内部存储,而我希望存储是IEnumerable<T>
iteslf。
好的,这听起来像是IEnumerator<T>
常常是ValueType
以及不知道先验IEnumerator<T>
的状态的共识,这通常是一个坏主意传递它。
我听过的最好的建议就是创建我自己的课程。还有其他建议吗?
答案 0 :(得分:6)
你肯定不能通过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);
}
}
}
尝试进行一些更改:
using (List<int>.Enumerator iterator = list.GetEnumerator())
和
using (IEnumerator<int> iterator = list.GetEnumerator())
尝试预测每种情况下的结果:)
现在不可否认,这是一个特别邪恶的例子,但它确实展示了一些与传递可变状态相关的极端案例。我强烈建议您在“中心”方法中执行所有迭代,只需使用当前值调用适当的其他方法。
答案 1 :(得分:2)
我强烈建议不要通过调查员本身;除了需要现值之外,你有什么理由呢?
除非我遗漏了一些明显的东西,否则我建议你的实用程序函数只是将你枚举的类型作为参数,然后有一个外部foreach
循环来处理实际的枚举。
也许你可以提供一些额外的信息,说明你到目前为止做出这个设计决定的原因。
答案 2 :(得分:2)
听起来像您可能会因使用事件而受益,因此您可以将要处理的项目的通知推送给听众。常规.NET事件按订阅顺序处理,因此如果需要订购,您可能会采用更明确的方法。
您可能还想查看Reactive Framework。
答案 3 :(得分:1)
如果我理解正确,你有很多方法可以在序列上调用MoveNext,你希望这些方法相互合作,所以你传递IEnumerator<T>
。正如你所提到的,这里肯定有一些紧耦合,因为你希望枚举器在每个方法的入口处处于特定状态。这听起来像你在这里真正的东西就像Stream类,它既是一个集合(一种)和一个迭代器(有一个当前位置的概念)。我会在你自己的类中包装你的迭代和你需要的任何其他状态,并将各种方法作为该类的成员