Should I return IEnumerable<T>
from methods and properties only in cases when it is lazy evaluated?
Do you have guys any patterns when you return IEnumerable
, ICollection
and IList
?
Should I return IEnumerable<T>
from methods and properties only in cases when it is lazy evaluated?
Do you have guys any patterns when you return IEnumerable
, ICollection
and IList
?
I return IEnumerable whenever the caller will only need to iterate over the collection from start to finish. By using the most minimal possible interface, I ensure that the calling code is not too tightly coupled, and thus make it easier to change the code in the method or property later. If it still returns IEnumerable, nobody else has to care. If it returned List before and the new method internally represents things using, say, a HashSet, suddenly lots of other things have to change as well.
Therefore I always prefer to return collection interfaces rather than concrete collections, except in cases where the calling code really needs to know exactly what type of collection it's dealing with. I consider the operations the caller is going to need to be able to do, and find the most minimal interface which supports them.
Usually if it is a list (not lazy) I return IList. Say, I do it all the time when my method is expected to return the result as a collection. I do it because it clearly states in the method signature that it is a loaded list, not lazy evaluated one, but yet using interface does not expose the concrete type (array, list, read-only list, etc).
I return IEnumerable when I do any kind of transformation on a collection that is passed in (LINQ approach)
At the same time I use IEnumerable as a parameters in my methods just to state that "this function doesn't care, it just need to be able to go through". Of course I ensure that the IEnumerable is enumerated only once within my function.
You return IEnumerable<T>
if the result is supposed to be read only for the caller of your method.
IEnumerable<T>
should be returned in these cases:
Result doesn't matter if it's an array, list or any kind of collection, because consumer needs to iterate it only.
Result is typed using an implementation of IEnumerable<T>
, but public API doesn't force consumers to work with API-specific types so consumers keeps neutral using POCO.
Specific implementations of IEnumerable<T>
like ICollection<T>
, IList<T>
, List<T>
and so on, should be returned if result is expected to be a collection. That's consumers should be able to access enumerable members with an indexer, or they should modify the collection itself (adding, updating, removing, searching... items in the collection).
Choosing the right concretion in your typing for properties and return types is more about a good case analysis and just type what your consumers need.
For example, conceptually talking, some property should return a list, but a consumer shouldn't modify it, so, this property should return a ReadOnlyCollection<T>
but you'd type it as IList<T>
.
As I said above, good case analysis and keep it simple.
As a rule of thumb:
I return ICollection
if I am sure I always know the number of results I return. If the caller just enumerates, they can easily treat is as an IEnumerable
anyway. If the order of elements is anything else than random, I use IList
. I use IEnumerable
in other cases. With different implementations for one interface, I use the "loosest" interface rather than recopying results in order to meet a specific collection interface.