我有以下课程:
class CopyProvider<T> where T: IMyCloneable
{
private readonly T _original;
public CopyProvider(T original) => _original = original;
public T Current { get; private set; }
public bool MoveNext()
{
Current = _original.Clone();
return true;
}
}
现在,我想知道将此类声明为IEnumerator<T>
的实现是否是一个好习惯。从句法的角度来看,CopyProvider
确实符合要求,但是会违反IEnumerator
的语义吗?
或者,我也可以编写以下方法:
IEnumerable<T> ProvideCopies<T>(T original) where T: IMyCloneable
{
while(true)
yield return original.Clone();
}
的确,这会舒服得多。但是同样,我遇到了同样的问题:IEnumerable
的这种用法会破坏接口的语义吗?
还是应该考虑使用InfiniteEnumerator
和/或InfiniteEnumerable
实现单独的对象结构?但是,这将使我无法使用yield
和foreach
之类的C#语法糖。
我期待您的推荐。
答案 0 :(得分:1)
如果您的枚举永远不会停止产生结果,则最好要求开发人员明确说明要产生的最大金额是多少,从而消除开发人员使用{{ 1}}语法与您的枚举。例如
for each
或者,如果您是老学校:
IEnumerable<T> ProvideCopies<T>(T original, int howMany) where T: IMyCloneable<T>
{
return Enumerable.Range(1, howMany).Select(x => original.Clone());
}
那样,开发人员没有有义务消耗整个枚举,并且可以随时停止(即,您仍在屈服),但是您知道它会在某个时刻停止,而不是因为代码中的错误而导致代码永久性地阻塞生产的可能性。
如果您真的无法确定需要多少份副本,并且需要继续生成副本,直到有其他情况告诉您停止,那么IEnumerable<T> ProvideCopies<T>(T original, int howMany) where T: IMyCloneable<T>
{
for (var i = 0; i < howMany; i++)
yield return original.Clone();
}
会更适合该情况,因为它的目的是“一直听”,直到您IObservable<T>
为止。
答案 1 :(得分:-2)
是的,我认为这确实是不好的做法。线程将无法处理任何其他代码路径。这会给处理器带来很多负担。