我正在关注微软的Guidelines for Collections,我发现有几个部分难以理解:
X不要在公共API中使用ArrayList
或List<T>
。这是否意味着我应该完全避免返回List<T>
,或者我可以将其作为IEnumerable
/ IList
返回,但不能明确地返回List<T>
?
✓请尽可能使用最不专业的类型作为参数类型。将集合作为参数的大多数成员使用IEnumerable<T>
接口。在看到ReSharper抱怨“可能多次枚举IEnumerable”之后,我认为当我期待预先计算的有限的对象集合(即不是惰性流)时,采用(并返回)ICollection<T>
是一个更好的主意。 )。不是这样的吗?
✓使用Collection<T>
或Collection<T>
的子类来表示属性或返回表示读/写集合的值。为什么不使用ICollection<T>
?我认为接口比具体类更可取。
答案 0 :(得分:8)
这些guidleines的存在是为了促进设计方法的灵活性,它们接受的参数以及它们作为返回类型返回的内容。
如果从方法返回List<T>
,该方法永远不会返回不 List<T>
的任何内容。在某些情况下这可能没什么问题,但在其他情况下则不然。例如,考虑一种方法,该方法返回在特定时间段内登录的用户集合。如果此方法仅返回List<T>
,则必须在一次传递中获取并返回所有用户,因为这些是List
的语义:一旦方法返回,您将获得具有总计数的所有项目。这可能是一个问题,如果用户数量是几万 - 可能需要很长时间才能获得所有记录,并且它们可能占用大量内存。
如果此方法返回IEnumerable<T>
,则无法计算或立即获取所有项目 - 调用者可以遍历项目集合但不能一次性获取所有项目。这允许被调用的方法返回一个对象(实现IEnumerable<T>
),该对象收集sevaral小批量中的数据并按要求逐个返回。
此外,许多不同的集合类型实现IEnumerable<T>
,因此此方法的另一个实现可能实际上决定返回列表实例,强制转换为IEnumerable<T>
。调用方法不会知道或关心,因为它期望的是IEnumerable<T>
。硬编码列表类型不是这种情况 - 它不能与其他任何东西交换,因为它已经尽可能具体。
通常,泛型集合接口将是任何方法最灵活的输入参数/返回类型 - 一个接口将允许您以多种方式实现它,模拟它等等所以你有很多灵活控制传递或返回的内容。接口也不一定(必然)具有语义限制,随着产品的发展可能会变得不方便。
至于第一个建议,ArrayList
是一个非常糟糕的类型,在.NET 2.0之后不应该使用,因为泛型类型在各方面都要好得多。