我正在编写与此类似的代码:
public IEnumerable<T> Unfold<T>(this T seed)
{
while (true)
{
yield return [next (T)object in custom sequence];
}
}
显然,这种方法永远不会回归。 (C#编译器默默地允许这个,而R#给我警告“函数永远不会返回”。)
一般来说,错误设计是否提供了一个返回无数个项目的枚举器,而不提供停止枚举的方法?
此方案是否有任何特殊注意事项?纪念品? PERF?其他陷阱?
如果我们总是提供退出条件,哪些是选项? E.g:
Predicate<T> continue
(正如TakeWhile
所做的那样)Take
所做的那样)我们是否应该依赖Take(...)
之后呼叫TakeWhile(...)
/ Unfold(...)
的用户? (也许是首选方案,因为它利用了现有的Linq知识。)
如果代码要在公共API中发布,无论是原样(通用)还是作为此模式的特定实现,您会以不同的方式回答这个问题吗?
答案 0 :(得分:7)
只要您非常清楚地记录该方法永远不会完成迭代(当然,方法本身很快就会返回),那么我认为这很好。实际上,它可以使一些算法更整洁。我不相信有任何重要的内存/性能影响 - 尽管如果你在迭代器中引用“昂贵”的对象,那么将会捕获该引用。
总有滥用API的方法:只要你的文档清楚,我认为没问题。
答案 1 :(得分:6)
“一般来说,这是不好的设计 提供返回的枚举器 无限量的物品,没有 提供一种停止枚举的方法?“
代码的消费者可以始终停止枚举(例如使用break或其他方式)。如果您的枚举器返回并且无限序列,这并不意味着枚举器的客户端以某种方式被强制永远不会破坏枚举,实际上您不能创建一个保证由客户端完全枚举的枚举器。
我们应该依赖用户打电话吗? 以(...)/ TakeWhile(...)之后 展开(...)? (也许是首选 选项,因为它利用现有的 林克知识。)
是的,只要您在文档中明确指出枚举器返回并且无限顺序和断开枚举是调用者的责任,一切都应该没问题。
返回无限序列并不是一个坏主意,功能编程语言已经做了很长时间了。
答案 2 :(得分:2)
我同意乔恩。编译器将您的方法转换为实现简单状态机的类,该状态机保持对当前值的引用(即将通过Current属性返回的值)。我多次使用这种方法来简化代码。如果你清楚地记录了方法的行为,它应该可以正常工作。
答案 3 :(得分:0)
我不会在公共API中使用无限枚举器。包含我自己的C#程序员太习惯了foreach循环。这也与.NET Framework一致;注意Enumerable.Range和Enumerable.Repeat方法如何使用参数来限制Enumerable中的项目数。 Microsoft选择使用Enumerable.Repeat(“”,10)而不是Enumerable.Repeat(“”)。使用(10)来避免无限枚举,我会坚持他们的设计选择。