-1

I read a lot about why it is better to return an IEnumerable instead of an IList (or something like this). But now I stuck at some point.

Consider something like this: I have some functions that do multiple enumerations and therefore take an IReadOnlyCollection as a parameter, create a new List and return it as an IEnumerable.

IEnumerable<int> Foo1(IReadOnlyCollection<int> bar)
{
   bar.Any();
   bar.First();
   return new List<int>() {1, 2, 3};
}
IEnumerable<int> Foo2(IReadOnlyCollection<int> bar)
{
   bar.Any();
   bar.First();
   return new List<int>() {1, 2, 3};
}
IEnumerable Foo3 ...

Now if I want to call them one after another I have to do something like this

var tmp = Foo1(new List<int>() {1, 2, 3});
tmp = Foo2(tmp.ToList());
tmp = Foo3(tmp.ToList());
tmp = Foo4(tmp.ToList());
tmp = Foo5(tmp.ToList());

That means I have to create a 11 lists. The first one, one in every function and one for every function call. But in fact it would be enough to create 6 lists. Is there a better way or is this simply a possible drawback when returning IEnumerable?

user1660514
  • 267
  • 3
  • 7
  • Why are you calling `ToList()` for every call? – Blorgbeard Oct 19 '14 at 23:36
  • 1
    This is a terrible code example. Neither of your example methods actually use the object passed, other than to call a couple of methods (Any and First) which ultimately have no effect on the output of the program. It is impossible to understand what you are actually trying to achieve here, which means it's impossible to help. Finally, note that the most common scenario for returning IEnumerable (or rather, IEnumerable) is to write an iterator method, using "yield return". Thus, if processing an input enumeration, no copy of the data is made...it's just changed on its way through the method. – Peter Duniho Oct 19 '14 at 23:58

1 Answers1

2

In general, this is simply a tradeoff inherent in returning IEnumerable.

The advantage of returning IEnumerable is that you can change your Foo() implementation to return nearly any type of collection (or even a lazy sequence with yield return or LINQ) without changing the API. When creating an interface, it's important to balance this advantage against the fact that consumers of an IEnumerable API who want to enumerate it multiple times will always have to convert it to a collection.

Even more generally, returning a more specific type (e. g. List over IList) is most useful to consumers and most challenging in terms of maintaining the API. Some things to consider:

  • Is there any real use-case for returning a lazily-evaluated sequence? If not, consumers will likely appreciate getting a collection type instead of IEnumerable
  • Is this order of your result set important? In this case, List, IList, or IReadOnlyList is often preferable over something like ICollection or IReadOnlyCollection?
  • Is the returned collection guaranteed to be newly generated or might it be cached / a view over internal data? If the latter? If you could see converting to the latter pattern in the future, then you'll want to be sure to return a read-only interface or collection type.

If you're just worried about the performance of creating new lists (which shouldn't be a real concern in nearly all cases), you can always create an extension as follows:

public static IReadOnlyCollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> @this)
{
    return @this as IReadOnlyCollection<T> ?? @this.ToArray();
}
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152