Return Types for Methods that Return Collections
In a tip from a couple of months ago, I suggested that if you have a method or property that returns a collection, then your method should return only one of three interfaces: IList, IQueryable or IEnumerable. (Returning an interface allows you to change the type of the collection used inside your method without breaking the clients that use your method.)
Not surprisingly, I got some interesting feedback from readers. One reader pointed out that if you're going to allow the client to update your collection, Microsoft recommends your method return ICollection. ICollection allows the client to add to the end of your collection, to clear your collection, and to remove specific objects from the collection; ICollection doesn't allow the client to insert or delete items at specific positions in your collection. In other words, ICollection allows the client to update the collection you return only by adding to it or by removing specific objects. I can see how that could be a better choice than IList, which allows the client to arbitrarily insert and remove items by position.
Side note: Interestingly, neither ICollection or IList supports one of my favorite methods, AddRange, which allows you to add a collection of items to the end of another collection (AddRange is only available on the List class itself). I'm fond enough of AddRange that I've created my own extension method that adds the method to any class that implements IList. I'll switch that extension method's definition over to using ICollection.
No one objected to my recommendation for using IQueryable with methods that return Entity Framework results. However, I realized I was being narrow-minded. You should use IQueryable to return the result of any LINQ query where you want to give the client the ability to extend the query by using the result in another LINQ query (this gives the compiler more options in optimizing the final query). That's going to be an Entity Framework result 90 percent of the time, but I should be as inclusive as possible.
However, another reader did suggest that, if you were only going to let the client read your collection, IReadOnlyList is a better choice than IEnumerable. Just like IEnumerable, IReadOnlyList allows the client to retrieve items at specific locations and to build For…Each loops to process the list. Declaring your method as returning IReadOnlyList does have the advantage of being more obvious than IEnumerable in communicating that your collection is read-only, though. Unfortunately, IReadOnlyList is only available in the Microsoft .NET Framework 4.5 and newer.
So here's the latest and greatest version of my advice: If your method or property is returning a collection and you want to allow the client to add or remove objects in a controlled way (add only at the end, remove only by object reference), return ICollection; if you want to give the client the ability to work with the items in your collection by position, return IList. If you're returning the results of a LINQ query and want to give the client the ability to use the result in another LINQ query in an efficient way, use IQueryable. For everything else (which just leaves read-only collections) use IReadOnlyList; if IReadOnlyList isn't available, use IEnumerable.
Posted by Peter Vogel on 09/23/2014 at 1:51 PM