Every time i see code with properties that return List<T>, IList<T>, ICollection<T> or any other of the types which allow you to modify the contents of a collection, i cringe a little. In most cases, the only reason to expose the contents of the collection is for read-only usage. You want people to be able to use the objects in the collection, but why on earth do so many developers continuously enable someone else to modify the internal state of the collection that they are holding?
The problem that i have with exposing a collection's values through a type which enables other pieces of code to modify the state of that collection is that it is effectively a pretty big breach of encapsulation. You no longer have sole control over the contents of the collection. Anyone can effectively add and remove elements from the collection, or even clear them entirely, without your object knowing about it. Obviously, this can cause subtle side-effects in the behavior of your object. Which can (and sooner or later will) lead to some quality time between you and your debugger. You also no longer have the ability to easily change the type of collection you're using which might prevent certain future improvements that you can make to a class. And in case you're wondering why you'd want to change the type of collection, check out an example where the benefit was huge.
In a lot of cases, people do this because they don't know any better or because it's the easiest thing to do. I can't tell you how many times i've seen people expose List<T> simply so that some calling code could use the ForEach method of that list. How long does it take to write a ForEach extension method for IEnumerable<T>? Granted, it should've been included in the .NET framework already but just because it's not doesn't mean you can't do so.
Here's my philosophy on exposing collections: if i'm writing a class that is responsible for holding a collection, i take away every ability to directly modify the contents of the collection. I typically expose the collection through an IEnumerable<T> property, and if necessary i will provide a specific AddXxx and RemoveXxx method. That's it. You can do every single thing you need to do with the collection through IEnumerable<T>'s extension methods and through the AddXxx and RemoveXxx methods that i provide. Meanwhile, i have every ability to choose the collection type that i want to use, or to modify it later on. Furthermore, i can eliminate the possibility of side-effects in my code due to unexpected externally caused mutations in the state of the collection.
The only situation in which i think it's OK to return a real collection type is if you have a method which is responsible for creating a list, but is not supposed to hold on to it. In that case, the created collection is clearly intended to be used in whatever way makes sense by the consumer. After all, you created the collection specifically for the consumer so they can do whatever they want with it. But if you need to hold a reference to the collection for some reason, then you probably also have more responsibilities than merely creating the collection. In that case, the collection is yours and you should encapsulate it as such.
Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #464