In a response to this question runefs suggested that "unless you have a very specific reason for using IList you should considere IEnumerable". Which do you use and why?
When I only need to enumerate the children, I use IEnumerable. If I happen to need Count, I use ICollection. I try to avoid that, though, because it exposes implementation details.
Always use the most restrictive interface that provides the features you need, because that gives you the most flexibility to change the implementation later. So, if IEnumerable<T>
is enough, then use that... if you need list-features, use IList<T>
.
And preferably use the strongly typed generic versions.
IEnumberable<T>
is read-only, you have to reconstruct the collection to make changes to it. On the other hand, IList<T>
is read-write. So if you expect a lot of changes to the collection, expose IList<T>
but if it's safe to assume that you won't modify it, go with IEnumerable<T>
.
IList<T>
is indeed a very beefy interface. I prefer to expose Collection<T>
-derived types. This is pretty much in line with what Jeffrey Richter suggests doing (don't have a book nearby, so can't specify page/chapter number): methods should accept the most common types as parameters and return the most "derived" types as return values.
The principle I follow is one I read a while back:
"Consume the simplest and expose the most complex"
(I'm sure this is really common and I'm mis-quoting it, if anyone can knows the source can you leave a comment or edit please...)
(Edited to add - well, here I am a couple of weeks later and I've just ran into this quote in a completely different context, it looks like it started as the Robustness Principle or Postel's Law -
Be conservative in what you do; be liberal in what you accept from others.
The original definition is for network communication over the internet, but I'm sure I've seen it repurposed for defining class contracts in OO.)
Basically, if you're defining a method for external consumption then the parameters should be the most basic type that gives you the functionality you require - in the case of your example this may mean taking in an IEnumerable instead of an IList. This gives client code the most flexibility over what they can pass in. On the other hand if you are exposing a property for external consumption then do so with the most complex type (IList or ICollection instead of IEnumerable) since this gives the client the most flexibility in the way they use the object.
I'm finding the conversation between myself and DrJokepu in the comments fascinating, but I also appreciate that this isn't supposed to be a discussion forum so I'll edit my answer to further outline the reasons behind my choice to buck the trend and suggest that you expose it as an IList (well a List actually, as you'll see). Let's say this is the class we are talking about:
public class Example
{
private List<int> _internal = new List<int>();
public /*To be decided*/ External
{
get { return _internal; }
}
}
So first of all let's assume that we are exposing External as an IEnumerable. The reasons I have seen for doing this in the other answers and comments are currently:
- IEnumerable is read-only
- IEnumerable is the defacto standard
- It reduces coupling so you can change the implementation
- You don't expose implementation details
While IEnumerable only exposes readonly functionality that doesn't make it readonly. The real type you are returning is easily found out by reflection or simply pausing a debugger and looking, so it is trivial to cast it back to List<>, the same applies to the FileStream example in the comments below. If you are trying to protect the member then pretending it is something else isn't the way to do it.
I don't believe it is the defacto standard. I can't find any code in the .NET 3.5 library where Microsoft had the option to return an concrete collection and returned an interface instead. IEnumerable is more common in 3.5 thanks to LINQ, but that is because they can't expose a more derived type, not because they don't want to.
Now, reducing coupling I agree with - to a point - basically this argument seems to be that you are telling the client that while the object you return is a list I want you to treat is as an IEnumerable just in case you decide to change the internal code later. Ignoring the problems with this and the fact that the real type is exposed anyway it still leaves the question of "why stop at IEnumerable?" if you return it as an object type then you'll have complete freedom to change the implementation to anything! This means that you must have made a decision about how much functionality the client code requires so either you are writing the client code, or the decision is based around arbitrary metrics.
Finally, as previously discussed, you can assume that implementation details are always exposed in .NET, especially if you are publicly exposing the object.
So, after that long diatribe there is one question left - Why expose it as a List<>? Well, why not? You haven't gained anything by exposing it as a IEnumerable, so why artificially limit the client code's ability to work with the object? Imagine if Microsoft had decided that the Controls collection of a Winforms Control should appear as IEnumerable instead of ControlCollection - you'd no longer be able to pass it to methods that require an IList, work on items at an arbitrary index, or see if it contains a particular control unless you cast it. Microsoft wouldn't really have gained anything, and it would just inconvenience you.
If a read-only collection is exposed via a property, then the conventional way to do it is to expose it as ReadOnlyCollection (or a derived class of that) wrapping whatever you have there. It exposes full capabilities of IList to the client, and yet it makes it very clear that it is read-only.