【问题标题】:Is it a bad practice implementing infinite enumerators and enumerables?实现无限枚举器和枚举器是一种不好的做法吗?
【发布时间】:2019-03-25 18:54:07
【问题描述】:

我有以下课程:

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&lt;T&gt; 的实现是否是一个好习惯。从句法上看,CopyProvider 确实符合要求,但会不会违反IEnumerator 语义?

或者,我也可以编写以下方法:

IEnumerable<T> ProvideCopies<T>(T original) where T: IMyCloneable
{
    while(true)
        yield return original.Clone();
}

确实,这样会舒服得多。但是,我又遇到了同样的问题:IEnumerable 的这种用法会破坏接口的语义吗?

或者我应该考虑使用InfiniteEnumerator 和/或InfiniteEnumerable 实现一个单独的对象结构?但是,这会阻止我使用像 yieldforeach 这样的 C# 语法糖。

我期待您的建议。

【问题讨论】:

标签: c# .net oop ienumerable ienumerator


【解决方案1】:

如果您的枚举永远不会停止产生结果,最好要求开发人员明确说明要生成的最大数量是多少,这样您就可以消除开发人员使用 @987654322 时出现无限循环的风险@ 语法与您的可枚举。例如

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&lt;T&gt; 将更适合这种情况,因为它旨在“倾听”直到你Dispose() 为止。

IObservable Interface

【讨论】:

    【解决方案2】:

    是的,我认为这确实是不好的做法。线程将无法处理任何其他代码路径。这会给处理器带来很多负担。

    【讨论】:

    • 问题不在于不停止/中断枚举“可数无穷大”是否不好;-)(另请参阅 dbc 对该问题的评论中给出的链接)
    猜你喜欢
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-20
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多