我在this帖子中找到了问题的解决方案 - 这让我在那里提出了新答案 - 并且 - 面对以下问题:
考虑ICollection
实现IEnumerable
,并且所有linq扩展都适用于这两个接口,是否有任何情况我可以通过使用IEnumerable
代替ICollection
而受益?
例如,非通用IEnumerable
不提供Count
扩展名。
两个ICollection
接口都可以。
鉴于所有ICollection
,在任何情况下,提供所有功能IEnumerable
实施 - 因为它本身实现了它 - 为什么我会选择IEnumerable
代替ICollection
?
与先前没有ICollection
的框架的向后兼容性?
答案 0 :(得分:4)
IEnumerable
为集合提供只读接口,ICollection
允许修改。另外IEnumerable
只需知道如何迭代元素。 ICollection
必须提供更多信息。
这在语义上是不同的。您并不总是希望提供修改集合的功能。
有一个IReadOnlyCollection
,但它没有实现ICollection
。这是C#的设计,ReadOnly
是一个不同的精简界面。
蒂姆提出的观点非常重要。 Count
的内部工作可能会有很大不同。 IEnumerable
不需要知道它跨越了多少元素。 Collection有一个Property,所以它必须知道它包含多少个元素。这是另一个重要的区别。
答案 1 :(得分:4)
我认为这里有两个问题要回答。
我何时需要IEnumerable<T>
?
与其他集合类型和一般语言不同,IEnumerable
上的查询是使用延迟评估执行的。这意味着您可以仅在枚举中执行多个相关查询。
值得注意的是,懒惰的评估与副作用没有很好的交互,因为多次枚举可能会产生不同的结果,在使用它时需要牢记这一点。在像C#这样的语言中,如果你不小心,懒惰的评估可能是一个非常强大的工具,但也是一个无法解释的行为的来源。
我什么时候不想要ICollection<T>
?
ICollection<T>
是一个可变接口,除其他外,它还公开了添加和删除方法。除非您希望外部事物改变对象的内容,否则您不想返回它。同样,出于同样的原因,你通常不希望将其作为参数传递。
如果您确实希望集合具有明显的可变性,请务必使用ICollection<T>
。
此外,与IEnumerable<T>
或IReadOnlyCollection<T>
不同,ICollection<T>
不是协变,这会降低某些用例中类型的灵活性。
非通用版本
对于这些接口的非泛型版本,情况有所改变。在这种情况下,两者之间唯一真正的区别是IEnumerable
提供的懒惰评估和ICollection
的热切评估。
我个人倾向于避免使用非通用版本,因为在值类型的情况下缺乏类型安全性和装箱/拆箱性能差。
<强>摘要强>
如果您想进行延迟评估,请使用IEnumerable<T>
。对于急切的评估和不变性,请使用IReadOnlyCollection<T>
。对于显式可变性,请使用ICollection<T>.
答案 2 :(得分:2)
我们的想法是使用满足要求的最简单的契约(接口):ICollection
是一个集合,IEnumerable
是一个序列。一个序列可能有延迟执行,它可能是无限的等等。接口IEnumerable
只是告诉你可以枚举序列,就是全部。这与ICollection
不同,IEnumerable
表示包含有限数量项目的实际集合。
如您所见,这些是完全不同的。您不能忽略这些契约的语义,只关注哪个接口继承了哪个接口。
如果您的算法只涉及枚举输入数据,那么它应该采用ICollection
。如果您通过合同处理集合(即,您希望集合而不是其他内容),那么您应该使用:after
。