On Exposing Generic List Or Generic Collection
So I was running FxCop on a library today and it decided to flag a problem, exposing List<T> publicly outside of a class. The recommendation was to use Collection<T>. The reasoning was sound, but there is something in the documentation that needs to be cleared up.
Just so you know, the reason is that List<T> is not really designed for inheritance. It can be inherited from (I have done that), but doing so has less value than inheriting from Collection<T>. Collection<T> has four protected virtuals, ClearItems (called by Clear), InsertItem (called by Add and Insert), RemoveItem (called by Remove and RemoveAt), and SetItem (called by the indexer set). If, for some reason, you were using List<T> and needed to change how any of these very essential methods of the collection work, you are up a creek without a paddle. Collection<T> uses List<T> internally and does basically nothing that List<T> does not do. It just allows for more flexibility. And in a public API, that is very important.
The solution listed in the msdn documentation for this, in my opinion, needs to be changed a little. It says the following: "To fix a violation of this rule, change the System.Collections.Generic.List type to one of the generic collections designed for inheritance." This is true, but I think you probably need to go further. And I think this further step is implied, though not clearly stated. Instead of exposing Collection<T>, expose a class which inherits from Collection<T>. If you want extensibility you cannot extend Collection<T> without inheriting from it. So, if you have a class called "Foo", don’t expose Collection<Foo> but FooCollection, which would inherit from Collection<Foo>.
Now, if you don’t do this, you are still not in huge trouble. Let’s say you expose Collection<Foo>, somebody uses it, and then you change it to a FooCollection. Everything should still compile and run fine. The runtime will cast FooCollection to Collection<Foo> without a problem. But that is not the ideal. Expose FooCollection initially and you stand less of a chance of confusing the consumers of your API.