Should I always return IEnumerable<T> instead of IList<T>?
C#IenumerableC# Problem Overview
When I'm writing my DAL or other code that returns a set of items, should I always make my return statement:
public IEnumerable<FooBar> GetRecentItems()
or
public IList<FooBar> GetRecentItems()
Currently, in my code I have been trying to use IEnumerable as much as possible but I'm not sure if this is best practice? It seemed right because I was returning the most generic datatype while still being descriptive of what it does, but perhaps this isn't correct to do.
C# Solutions
Solution 1 - C#
Framework design guidelines recommend using the class Collection
The reason this is preferred to a simple IList
is that IList
does not inform the caller if its read only or not.
If you return an IEnumerable<T>
instead, certain operations may be a little trickier for the caller to perform. Also you no longer will give the caller the flexibility to modify the collection, something that you may or may not want.
Keep in mind that LINQ contains a few tricks up its sleeve and will optimize certain calls based on the type they are performed on. So, for example, if you perform a Count
and the underlying collection is a List it will NOT walk through all the elements.
Personally, for an ORM I would probably stick with Collection<T>
as my return value.
Solution 2 - C#
It really depends on why you are using that specific interface.
For example, IList<T>
has several methods that aren't present in IEnumerable<T>
:
IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
and Properties:
T this[int index] { get; set; }
If you need these methods in any way, then by all means return IList<T>
.
Also, if the method that consumes your IEnumerable<T>
result is expecting an IList<T>
, it will save the CLR from considering any conversions required, thus optimizing the compiled code.
Solution 3 - C#
In general, you should require the most generic and return the most specific thing that you can. So if you have a method that takes a parameter, and you only really need what's available in IEnumerable
Be loose in what you require, and explicit in what you provide.
Solution 4 - C#
That depends...
Returning the least derived type (IEnumerable
) will leave you the most leeway to change the underlying implementation down the track.
Returning a more derived type (IList
) provides the users of your API with more operations on the result.
I would always suggest returning the least derived type that has all the operations your users are going to need... so basically, you first have to deremine what operations on the result make sense in the context of the API you are defining.
Solution 5 - C#
One thing to consider is that if you're using a deferred-execution LINQ statement to generate your IEnumerable<T>
, calling .ToList()
before you return from your method means that your items may be iterated twice - once to create the List, and once when the caller loops through, filters, or transforms your return value. When practical, I like to avoid converting the results of LINQ-to-Objects to a concrete List or Dictionary until I have to. If my caller needs a List, that's a single easy method call away - I don't need to make that decision for them, and that makes my code slightly more efficient in the cases where the caller is just doing a foreach.
Solution 6 - C#
List<T>
offers the calling code many more features, such as modifying the returned object and access by index. So the question boils down to: in your application's specific use case, do you WANT to support such uses (presumably by returning a freshly constructed collection!), for the caller's convenience -- or do you want speed for the simple case when all the caller needs is to loop through the collection and you can safely return a reference to a real underlying collection without fearing this will get it erroneously changed, etc?
Only you can answer this question, and only by understanding well what your callers will want to do with the return value, and how important performance is here (how big are the collections you would be copying, how likely is this to be a bottleneck, etc).
Solution 7 - C#
It's not so simple when you are talking about return values instead of input parameters. When it's an input parameter, you know exactly what you need to do. So, if you need to be able to iterate over the collection, you take an IEnumberable whereas if you need to add or remove, you take an IList.
In the case of a return value, it's tougher. What does your caller expect? If you return an IEnumerable, then he will not know a priori that he can make an IList out of it. But, if you return an IList, he will know that he can iterate over it. So, you have to take into account what your caller is going to do with the data. The functionality that your caller needs/expects is what should govern when making the decision on what to return.
Solution 8 - C#
>
>
> I think you can use either, but each has a use. Basically List
is IEnumerable
but you have
> count functionality, add element, remove element
>
> IEnumerable is not efficient for counting elements
If the collection is intended to be readonly, or the modification of the collection is controlled by the Parent
then returning an IList
just for Count
is not a good idea.
In Linq, there is a Count()
extension method on IEnumerable<T>
which inside the CLR will shortcut to .Count
if the underlying type is of IList
, so performance difference is negligible.
Generally I feel (opinion) it is better practice to return IEnumerable where possible, if you need to do additions then add these methods to the parent class, otherwise the consumer is then managing the collection within Model which violates the principles, e.g. manufacturer.Models.Add(model)
violates law of demeter. Of course these are just guidelines and not hard and fast rules, but until you have full grasps of applicability, following blindly is better than not following at all.
public interface IManufacturer
{
IEnumerable<Model> Models {get;}
void AddModel(Model model);
}
(Note: If using nNHibernate you might need to map to private IList using different accessors.)
Solution 9 - C#
TL; DR; – summary
- If you develop in-house software, do use the specific type(Like
List
) for the return values and the most generic type for input parameters even in case of collections. - If a method is a part of a redistributable library’s public API, use interfaces instead of concrete collection types to introduce both return values and input parameters.
- If a method returns a read-only collection, show that by using
IReadOnlyList
orIReadOnlyCollection
as the return value type.
Solution 10 - C#
I think you can use either, but each has a use. Basically List
is IEnumerable
but you have count functionality, Add element, remove element
IEnumerable
is not efficient for counting elements, or getting a specific element in the collection.
List
is a collection which is ideally suited to finding specific elements, easy to add elements, or remove them.
Generally I try to use List
where possible as this gives me more flexibility.
Use
List<FooBar> getRecentItems()
rather than
IList<FooBar> GetRecentItems()
Solution 11 - C#
as all have said it depends, if you don't want Add/Remove functioanlity at calling layer then i will vote for IEnumerable as it provides only iteration and basic functionality which in design prespective i like. Returning IList my votes are always againist it but it's mainly what you like and what not. in performance terms i think they are more of same.
Solution 12 - C#
If you do not counting in your external code it is always better to return IEnumerable
However if you need items count, don't forget that there is another layer between IEnumerable and IList - ICollection.
Solution 13 - C#
I might be a bit off here, seeing that no one else suggested it so far, but why don't you return an (I)Collection<T>
?
From what I remember, Collection<T>
was the preferred return type over List<T>
because it abstracts away the implementation. They all implement IEnumerable
, but that sounds to me a bit too low-level for the job.
Solution 14 - C#
I think the general rule is to use the more specific class to return, to avoid doing unneeded work and give your caller more options.
That said, I think it's more important to consider the code in front of you which you are writing than the code the next guy will write (within reason.) This is because you can make assumptions about the code that already exists.
Remember that moving UP to a collection from IEnumerable in an interface will work, moving down to IEnumerable from a collection will break existing code.
If these opinions all seem conflicted, it's because the decision is subjective.
Solution 15 - C#
IEnumerable<T>
contains a small subset of what is inside List<T>
, which contains the same stuff as IEnumerable<T>
but more! You only use IEnumerable<T>
if you want a smaller set of features. Use List<T>
if you plan to use a larger, richer set of features.
The Pizza Explanation
Here is a much more comprehensive explanation of why you would use an Interface like IEnumerable<T>
versus List<T>
, or vise versa, when instantiating objects in C languages like Microsoft C#.
Think of Interfaces like IEnumerable<T>
and IList<T>
as the individual ingredients in a pizza (pepperoni, mushrooms, black olives...) and concrete classes like List<T>
as the pizza. List<T>
is in fact a Supreme Pizza that always contains all the Interface ingredients combined (ICollection, IEnumerable, IList, etc).
What you get as far as a pizza and its toppings is determined by how you "type" your list when you create its object reference in memory. You have to declare the type of pizza you are cooking as follows:
// Pepperoni Pizza: This gives you a single Interface's members,
// or a pizza with one topping because List<T> is limited to acting like an IEnumerable<T> type.
IEnumerable<string> pepperoniPizza = new List<string>();
// Supreme Pizza: This gives you access to ALL 8 Interface members combined
// or a pizza with ALL the ingredients because List type uses all Interfaces!!
List<string> supremePizza = new List<string>();
Note you cannot instantiate an Interface as itself (or eat raw pepperoni). When you instantiate List<T>
as one Interface type, or IEnumerable<T>
, you only have access to its Implementations and get the pepperoni pizza with one topping. You can only access IEnumerable<T>
members and cannot see all the other Interface members in List<T>
. When List<T>
is instantiated as List<T>
it implements all 8 Interfaces, so it has access to all the members of all the Interfaces it has implemented (or a Supreme Pizza toppings)!
Here is the List<T>
class, showing you WHY that is. Notice the List<T>
in the .NET Library has implemented all the other Interfaces!! Notice IEnumerable<T>
is just a small section of all the Interface members it has implemented.
public class List<T> :
ICollection<T>,
IEnumerable<T>,
IEnumerable,
IList<T>,
IReadOnlyCollection<T>,
IReadOnlyList<T>,
ICollection,
IList
{
public List();
public List(IEnumerable<T> collection);
public List(int capacity);
public T this[int index] { get; set; }
public int Count { get; }
public int Capacity { get; set; }
public void Add(T item);
public void AddRange(IEnumerable<T> collection);
public ReadOnlyCollection<T> AsReadOnly();
public bool Exists(Predicate<T> match);
public T Find(Predicate<T> match);
public void ForEach(Action<T> action);
public void RemoveAt(int index);
public void Sort(Comparison<T> comparison);
// ......and much more....
}
So why NOT instantiate List<T>
as List<T>
ALL THE TIME?
Instantiating a List<T>
as List<T>
gives you access to all Interface members! But you might not need everything. Choosing one Interface type allows your application to store a smaller object with less members and keeps your application tight. Who needs Supreme Pizza every time?
But there is a second reason for using Interface types: Flexibility. Because other types in .NET, including your own custom ones, might use the same "popular" Interface type, it means you can later substitute your List<T>
type with any other type that implements, say IEnumerable<T>
. If your variable is an Interface type, you can now switch out the object created with something other than List<T>
. Dependency Injection is a good example of this type of flexibility using Interfaces rather than concrete types, and why you might want to create objects using Interfaces.