代码之家  ›  专栏  ›  技术社区  ›  Christoffer Lette

如何设计一个返回(理论上)无限数量项的枚举器?

  •  6
  • Christoffer Lette  · 技术社区  · 16 年前

    我正在编写类似于此的代码:

    public IEnumerable<T> Unfold<T>(this T seed)
    {
        while (true)
        {
            yield return [next (T)object in custom sequence];
        }
    }
    

    显然,这个方法永远不会返回。(C编译器默许这一点,而R则警告我 “函数从不返回” )

    一般来说,是吗 坏的 设计为提供返回无限数量项的枚举器,而不提供停止枚举的方法?

    对于这种情况有什么特别的考虑吗?Mem?Perf?其他什么?

    如果我们总是提供一个退出条件,那么有哪些选择?例如:

    • 表示包含或独占边界的T类型对象
    • Predicate<T> continue (AS) TakeWhile 做)
    • 伯爵(如 Take 做)

    我们应该依靠用户呼叫吗 Take(...) / TakeWhile(...) 之后 Unfold(...) ?(可能是首选方案,因为它利用了现有的LINQ知识。)

    如果代码要在公共API中发布,您会以不同的方式回答这个问题吗?要么是按原样(通用)发布,要么是作为该模式的特定实现发布?

    4 回复  |  直到 11 年前
        1
  •  7
  •   Jon Skeet    16 年前

    只要您非常清楚地记录该方法永远不会完成迭代(当然,方法本身返回非常快),那么我认为它是好的。实际上,它可以使一些算法更整洁。我不认为存在任何重要的内存/性能影响-尽管如果您在迭代器中引用一个“昂贵”的对象,那么将捕获该引用。

    有很多滥用API的方法:只要你的文档清晰,我认为没问题。

        2
  •  6
  •   Pop Catalin    16 年前

    “一般来说,设计不好吗? 提供返回 无限数量的项目,没有 提供停止枚举的方法?“

    代码的使用者,可以 总是 停止枚举(例如使用break或其他方法)。如果枚举器返回无限序列,这并不意味着枚举器的客户机在某种程度上被强制从不破坏枚举,实际上,您不能生成保证由客户机完全枚举的枚举器。

    我们应该依靠用户呼叫吗 take(…)/takewhile(…)after后 展开(…)?(也许是首选 选项,因为它利用现有的 Linq知识。)

    是的,只要您在文档中明确指定枚举器返回和无限序列以及破坏枚举是调用方的责任,一切都应该正常。

    返回无限序列不是一个坏主意,函数编程语言已经做了很长时间了。

        3
  •  2
  •   aku    16 年前

    我同意乔恩的观点。编译器将方法转换为实现简单状态机的类,该状态机保持对当前值(即将通过当前属性返回的值)的引用。我多次使用这种方法来简化代码。如果您清楚地记录了方法的行为,它应该可以正常工作。

        4
  •  0
  •   Dan Goldstein    16 年前

    我不会在公共API中使用无限枚举器。C包括我自己在内的程序员太习惯foreach循环了。这也与.NET框架一致;请注意Enumerable.Range和Enumerable.Repeat方法如何使用参数来限制Enumerable中的项数。Microsoft选择使用Enumerable.Repeat(“”,10)而不是Enumerable.Repeat(“”)。Take(10)以避免无限枚举,我将坚持他们的设计选择。