Unless you specifically want to expose a List<T> via a public interface (either as a return type or as a method argument), it’s a better idea to expose an IList<T>, ICollection<T>, or even an IEnumerable<T> depending on your needs. Recently I had to implement a generic list class that implemented property notifications and for this purpose I wrote a collection class that implemented IList<T> which by the way implements both ICollection<T> and IEnumerable<T>. I thought it’d be a simple matter to change members of certain types that used a List<T> to use this new collection class.
Unfortunately, I found that there were several methods in containing classes as well as calling classes that expected List<T> objects (even though the callers only used IList<T> or ICollection<T> members). Eventually I ended up having to change calling code and utility helper methods to use an IList<T> or ICollection<T> as appropriate. (Note that exposing the notification list was out of the question as it was not accessible to some of the callers and it is not good practice anyway).
In some cases the code used List<T> specific methods like Find, but if you have LINQ available then you don’t need to use the List<T> methods since you have alternate and usually more useful extension methods that you can use. I suppose I am over-specializing here by talking about List<T> in particular because it’s probably a good general practice to always expose the least derived class that you really need to.
Note that if you really need to expose a solid class without letting the users change the collection, then using ReadOnlyCollection<T> would be the correct approach compared to directly exposing the List<T> or Collection<T> object or their related interfaces like IList<T>.
Good point. I typically manage list types internally using List and then only expose a readonly property of that list using the AsReadOnly() method, like so:
public IList MyTypes
{
get { return _myTypes.AsReadOnly(); }
}
I find this to be the best approach for most of my projects and it prevents me from creating crap logic to manage the lists outside their scope. 🙂
Good post!
Oops, I meant:
public IList MyTypes
{
get { return _myTypes.AsReadOnly(); }
}
Even with LINQ available, it drives me nuts that you can’t call things like Find on the generic IList. In my current project, we just said “screw it” and made it standard to return List.