Generic and specific return types
It is often preferred to work with as generic types as possible. Doing that opens up for more flexibility and being able to modify parts of the code without effecting any other parts. One example of this is IEnumerable<T> which is implemented by several generic collection types, such as HashSet<T>, List<T>, and LinkedList<T>.
If you write a method that works with a List<T> internally and returns it as an IEnumerable<T> the caller does not need know that it is actually a List<T> you are using. And if you later decide to change your implementation to use a different type internally the caller does not need to be updated as long as the new type also implements IEnumerable<T>.
This might have you think that you should always return IEnumerable<T> when possible. But this might come back and bite you.
The multiple enumeration issue
Whenever you iterate over a collection via the IEnumerable interface it gets Enumerated. This means that an Enumerator object is created that flattens the collection so that members can be accessed sequentially. If this is done more than once you are causing extra work to be performed.
IEnumerable<string> names = GetNames(); foreach (var name in names) { Console.WriteLine(name); } var sb = new StringBuilder(); foreach (var name in names) { sb.Append(name).Append(" "); }
The above code Enumerates the name enumerable twice. In the best case this just introduces some extra work. But it can get really nasty if GetNames returns a database Query. This will make the code evaluate the Query twice, possibly even returning different results each time.
Avoiding multiple enumerations
Fortunatelly it is quite easy to avoid multiple enumerations. The calling code can force the enumeration to happen once during variable initialization.
IList<string> names = GetNames().ToList(); ...
With this change the enumeration will only happen once and the rest of the code can stay the same. The ToList method will allocate a new List and populate it with the strings returned from the Enumerator.
The price of being generic
Now, assume the GetNames method actually do use a List<string> internally and returns it as an IEnumerable<string> but then the caller calls the ToList method, isn’t that just adding extra complexity? Yes! That is exactly right. And not only that, the call to ToList will create a new List<string> which will be populated with the exact same elements that already exists in the original List. So there is an efficiency penalty involved as well.
So what to do? Well, that depends. If you are writing a library that is aimed for users outside of your team or organization, in other words where you don’t know how the returned type will be used and it is important that your code is flexible while the interface is stable, then you probably should return an IEnumerable<T>.
But if you are in control of all the source code involved, then you can afford to be more specific in what types you return.