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.

Comments

Anderson 2006-12-14 12:46:45

I think with the addition of generics, creating a strongly typed collection class became more of a question of taste than any real added value. A typical implementation of FooCollection would only be the following:

public class FooCollection : Collection<Foo>{}

And that is it! Really here all you are doing is adding another level of inheritance that is not necessary. You aren’t adding any real code value like you would have in C# 1.0 when you were really providing strongly typed methods for Add, Insert, etc.

This all being said, I personally choose to add this inheritance layer because I like the style, but I don’t think it is a suggestion I would make to everyone in every situation.

(P.S.... your comments box doesn’t seem to think some characters are safe. Ahh the disadvantages of writing our own software, no?)