C # : List < T > 和 Collection < T > 之间的区别(CA1002,不要公开通用列表)

尝试在这里的一个项目上运行 Run Code Analysis,得到了一些类似这样的警告:

CA1002: Microsoft 设计: 更改“ 有些类,有些受保护的或公共财产”中的“ List < SomType >”以使用 Collection、 ReadOnlyCollection 或 KeyedCollection

为什么我应该使用 Collection<T>而不是 List<T>?当我查看 msdn 文档时,它们看起来几乎相等。在阅读了警告的错误帮助之后,我发现

System.Collections.Generic.List (T) _ 是为性能而非继承而设计的通用集合,因此不包含任何虚拟成员。

但这到底意味着什么? 我应该做什么呢?

我是否应该继续在内部使用 List<T>,然后在属性中返回一个 new Collection<T>(someList)?或者我应该开始使用 Collection<T>而不是 List<T>

72446 次浏览

Collection exposes some virtual members (insert, remove, set, clear) that you can override and provide additional functionality (such as notification events) when the collection is changed.

You may not need this now, but it is a common requirement for classes that contain collections, so it's best to plan for it in advance. Because Collection is designed with extensibility in mind it's very flexible. If in the future you decide you need some extra feature in the collection you can just extend it without any change to the public interface of the class. If you had used a list, you would have had to change it to a collection which means it would have broken all of the callers of your class because they would have to be changed to use lists to.

List on the other hand is designed with performance in mind, so should only be used in specific cases where performance is very important. Because it is not extensible future changes to anything using a list will break everything else dependant on it. Normally List should only be used internally within very low level classes and not exposed to anything to reduce the chance of future breaking changes.

In short, the generic list does not have virtual methods for Add, Remove etc, as it was designed to be fast, not extensible. This means that you cannot swap this concrete implementation out for a useful subclass (even though you can subclass it as it is not sealed).

Therefore, by exposing the List itself, you can never extend your collection to track add or remove operations (for example) without breaking the public contract of the class.

By exposing your collection as an IList or some-such, you can still use the List as the actual backing-store, but you retain future extensibility as you can swap out the concerete implementation later without changing the public contract of your class.