这个问题是另一个question的背叛,我提出了在迭代它时通过修改对象来滥用IEnumerable接口。
普遍的共识是,任何实现IEnumerable的东西都不应该是幂等的。但是.net支持使用foreach语句编译时间鸭子。提供IEnumerator GetEnumerator()方法的任何对象都可以在foreach语句中使用。
GetEnumerator方法应该是幂等的,还是在它实现IEnumerable时呢?
编辑(已添加上下文)
为了对此进行一些上下文,我建议的是,当遍历队列时,每个项目都会随着它的出现而出列。此外,在调用GetEnumerator之后推送到队列的任何新对象仍将被迭代。
答案 0 :(得分:3)
type 不是幂等的 - 甚至没有多大意义;你可能意味着不可改变,但目前尚不清楚。这是GetEnumerator
方法本身,通常是幂等的。
虽然我会说通常是这种情况,但我可以设想一种特殊情况,即使用非幂等GetEnumerator
方法是有意义的。例如,可能是您拥有的数据只能读取一次(因为它是从Web服务器流式传输的,它不会再次为同一个请求提供服务,或类似的东西)。在这种情况下,GetEnumerator
必须有效地使数据源无效,以便将来的调用会引发异常。
当然,这些类型和方法应该非常仔细地记录下来,但我认为它们是合理的。
答案 1 :(得分:3)
这个讨论很古老,据我所知,没有共识。
请不要混淆(运行时)Duck-Typing的概念与滥用编译器支持的foreach
以支持您所需的语义。
你似乎混淆的另一个概念是幂等与不变。根据您的措辞,您尝试描述第二个,这意味着在枚举期间提供枚举器的对象会被修改。另一方面,Idempotence意味着你的枚举器,当被调用两次时会产生相同的结果。
现在我们已经清楚了,你需要仔细决定你的IEnumerable操作应该支持的语义。某些枚举很难使幂等(即涉及缓存),并且通常属于以下类别之一:
另一方面,这只涉及“来源”操作。如果使用枚举器实现过滤或转换操作,则应始终尝试使它们具有幂等性。
答案 2 :(得分:0)
您似乎想要一个队列类,您可以从中将所有项目排成一行。
这个想法本身并没有错;我只是质疑您是否愿意专门使用GetEnumerator
来实现您所追求的目标。
为什么不简单地编写一个更明确的方法呢?例如,DequeueAll
或类似的东西。
示例:
// Just a simplistic example. Not the way I'd actually write it.
class CustomQueue<T> : Queue<T>
{
public IEnumerable<T> DequeueAll()
{
while (Count > 0)
{
yield return Dequeue();
}
}
}
(请注意,上面甚至可以是扩展方法,如果它实际上代表了您想要的仅功能,而不仅仅是{{ 1}}。)
通过这种方式,您仍然可以获得“干净”的代码,我怀疑您正在追踪,而没有非幂等Queue<T>
的{潜在]混淆:
GetEnumerator
答案 3 :(得分:0)
我建议在集合上使用ForEach不应该更改它,除非集合类型的名称暗示将要发生。我想到的问题是,如果执行一个方法将一个集合用于可枚举的东西(例如允许“For Each Foo in MyThing.DequeueAsEnum”),应该返回什么。如果DequeueAsEnum返回一个iEnumerable,那么有人可能会想到“Dim myIEnumerable As IEnumerable = MyThing.DequeueAsEnum”,然后在两个不相交的For-Each循环中使用MyIEnumerable。如果DequeueAsEnum返回一个类型EnumerableOnlyOnce,那么它的返回应该只被枚举一次就会更清楚一些。可以肯定的是,在较新的C#和VB.Net方言中隐式输入的存在使得有人可能在不应该将函数返回给变量时更有可能,但我不知道如何防止它。
顺便说一句,在许多情况下,防止将类引用存储到变量中会有所帮助;有没有办法以这样的方式声明一个类,外部代码可以使用该类类型的表达式,但不能声明它的变量?