Should I always return IEnumerable<T> instead of IList<T>?
Asked Answered
W

15

129

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.

Waldrop answered 2/7, 2009 at 5:15 Comment(5)
Is it List<T> or IList<T> you are asking about? The title and question says different things...Gavel
When ever possible user interface IEnumerable or Ilist instaead of concerete type.Degauss
I return collections as List<T>. I don't see the need to return IEnumberable<T> since you can extract that from List<T>Pyrotechnic
see also: https://mcmap.net/q/120989/-ienumerable-lt-t-gt-as-return-typeMettle
possible duplicate of ienumerablet-as-return-typeBordelaise
R
51

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.

Rile answered 2/7, 2009 at 5:29 Comment(3)
@Jon FDG recommend using Collection<T> or ReadOnlyCollection<T> as a return value for collection types see my answer.Herv
You aren't clear what you mean in your last sentence when you say "it will save the CLR". What will save it, using IEnumerable vs. IList? Can you make that clearer?Henriquez
@CoffeeAddict Three years after this answer I think you're right -- that last part is vague. If a method that expects an IList<T> as a parameter gets an IEnumerable<T> the IEnumerable has to be wrapped manually in a new List<T> or other IList<T> implementor, and that work won't be done by the CLR for you. The opposite -- a method expecting an IEnumerable<T> getting an IList<T>, may have to do some unboxing but on hindsight might not need to because IList<T> implements IEnumerable<T>.Rile
H
79

Framework design guidelines recommend using the class Collection when you need to return a collection that is modifiable by the caller or ReadOnlyCollection for read only collections.

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.

Herv answered 3/7, 2009 at 5:49 Comment(1)
The Guidelines for Collections contain a more detailed list of DOs and DONTs.Ivon
R
51

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.

Rile answered 2/7, 2009 at 5:29 Comment(3)
@Jon FDG recommend using Collection<T> or ReadOnlyCollection<T> as a return value for collection types see my answer.Herv
You aren't clear what you mean in your last sentence when you say "it will save the CLR". What will save it, using IEnumerable vs. IList? Can you make that clearer?Henriquez
@CoffeeAddict Three years after this answer I think you're right -- that last part is vague. If a method that expects an IList<T> as a parameter gets an IEnumerable<T> the IEnumerable has to be wrapped manually in a new List<T> or other IList<T> implementor, and that work won't be done by the CLR for you. The opposite -- a method expecting an IEnumerable<T> getting an IList<T>, may have to do some unboxing but on hindsight might not need to because IList<T> implements IEnumerable<T>.Rile
L
51

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, then that should be your parameter type. If your method could return either an IList or an IEnumerable, prefer returning IList. This ensures that it is usable by the widest range of consumers.

Be loose in what you require, and explicit in what you provide.

Lowminded answered 17/12, 2009 at 19:49 Comment(8)
I have come to the opposite conclusion: that one should accept specific types, and return general types. You may be right however that more broadly applicable methods are better than more constrained methods. I will have to think about this more.Ardennes
The justification for accepting general types as input is that it allows you to work with the broadest range of input possible in order to get as much reuse out of a component as possible. On the other hand, since you already know exactly what kind of object you have handy, there's not much point in masking it.Lowminded
I think I agree with having more general parameters, but what is your reasoning for returning something less general?Ardennes
Okay, let me try this another way. Why would you throw away information? If you only care about the result being IEnumerable<T>, does it hurt you in any way to know that it's an IList<T>? No, it doesn't. It may be superfluous information in some cases, but it does you no harm. Now for the benefit. If you return a List or IList, I can tell immediately that the collection has already been retrieved, something I can't know with an IEnumerable. This may or may not be useful information but once again, why would you throw away information? If you know extra information about something, pass it on.Lowminded
In retrospect, I'm surprised no-one ever called me on that one. An IEnumerable WOULD have been retrieved already. An IQueryable could be returned in an unenumerated state, however. So perhaps a better example would returning IQueryable vs IEnumerable. Returning the more specific IQueryable would allow for further composition, whereas returning IEnumerable would force immediate enumeration, and decrease the composability of the method.Lowminded
I'm not certain this is correct. Many LINQ methods perform lazy evaluation and return IEnumerable. There is no guarantee that the data has been enumerated.Headdress
I think the issue is that if you add more conditions on top of an IEnumerable, it may evaluate up to that point BEFORE applying the additional conditions, even if it hasn't enumerated already. I think this may be implementation-specific, but I haven't looked under the hood to be sure. I think the safest thing is to assume that an IQueryable is "fair game" for further refinement without penalty, but the same cannot be said of IEnumerable. You can modify it, but you can't guarantee the "without penalty" part.Lowminded
I'll just keep on beating this horse. I realize I could be clearer. An IEnumerable will not necessarily have been evaluated "already". Both IQueryable and IEnumerable support deferred execution. The main difference is that conditions tacked onto an IQueryable can still find their way into a SQL query if your IQueryable came from an ORM. An IEnumerable may not have evaluated yet, but additional predicates added onto it would NOT find their way into the query, and would be applied in a second round after the initial retrieval. There... I think that's clearer now.Lowminded
V
29

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.

Vomer answered 2/7, 2009 at 5:29 Comment(3)
nice generic answer as it applies to other methods too.Pare
I know this answer is very old ... but it seems to contradict the documentation: "If neither the IDictionary<TKey, TValue> interface nor the IList<T> interface meet the requirements of the required collection, derive the new collection class from the ICollection<T> interface instead for more flexibility" This seems to imply that the more derived type should be preferred. (msdn.microsoft.com/en-us/library/92t2ye13(v=vs.110).aspx)\Thirteen
The thing is, you don't know what the users might need. So why not return what you have? If you have a List and you return an IEnumerable, you just handicapped the caller. If he needs a List, he is going to have to iterate through the entire collection to get a list.... when it was already a List. If he just needs an IEnumerable, he can treat the List like one with no problems. I don't see the point in not returning the most usable object.Octavie
B
20

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.

Bachelor answered 2/7, 2009 at 5:48 Comment(3)
@Joel Mueller, I usually would call ToList() on them anyway. I generally don't like exposing IQueryable to the rest of my projects.Waldrop
I was referring more to LINQ-to-Objects, where IQueryable doesn't generally enter the picture. When a database is involved, ToList() becomes more necessary, because otherwise you risk closing your connection before iterating, which doesn't work very well. However, when that isn't an issue, it's pretty easy to expose IQueryable as an IEnumerable without forcing an extra iteration when you want to hide the IQueryable.Bachelor
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. - you don't know what the caller could do, what if he iterates twice? Your deferred operation would be done twice.Enneagon
C
10

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).

Chidester answered 2/7, 2009 at 5:28 Comment(3)
"safely return a reference to a real underlying collection without fearing this will get it erroneously changed" - Even if you return IEnumerable<T>, couldn't they simply cast it back to a List<T> and change it?Earthenware
Not every IEnumarable<T> is also a List<T>. If the object returned is not of a type that inherits from List<T> or implements IList<T> this would result in a InvalidCastException.Doorplate
List<T> has the problem that it locks you in to a particular implementation Collection<T> or ReadOnlyCollection<T> are preferredHerv
L
5

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.)

Lithography answered 2/7, 2009 at 6:21 Comment(0)
F
4

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.

Freon answered 2/7, 2009 at 5:28 Comment(0)
B
1

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 or IReadOnlyCollection as the return value type.

More

Byrd answered 6/3, 2020 at 6:30 Comment(0)
A
0

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()

Adz answered 2/7, 2009 at 5:26 Comment(0)
D
0

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.

Degauss answered 2/7, 2009 at 5:34 Comment(0)
S
0

If you do not counting in your external code it is always better to return IEnumerable, because later you can change your implementation (without external code impact), for example, for yield iterator logic and conserve memory resources (very good language feature by the way).

However if you need items count, don't forget that there is another layer between IEnumerable and IList - ICollection.

Spot answered 2/7, 2009 at 7:31 Comment(0)
C
0

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.

Corwun answered 2/7, 2009 at 7:48 Comment(0)
C
0

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.

Cyrstalcyrus answered 4/10, 2012 at 14:39 Comment(0)
C
0

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!!

IList<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 like 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 IList<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 including IList!! But IEnumerable<T> implements just a small subsection of those List Interface members.

public class List<T> :

    ICollection<T>,
    IEnumerable<T>,
    IEnumerable,
    IList<T>,
    IReadOnlyCollection<T>,
    IReadOnlyList<T>,
    ICollection,
    IList

{
// List<T> types implement all these goodies and more!
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.

Catamaran answered 28/9, 2021 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.