Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a mistake to return a list if the return type is an enumerable

Tags:

c#

I have often the case where I want to return an Enumerable<T> from a method or a property. To build the returning Enumerable<T>, I use a List<T>-instance. After filling the list, I return the list.

I always thought that this is enough. But it exists the possibility that the caller casts the resulting Enumerable<T> back into the List<T> and begins to work further with it. If in a later time I change the implementation of my method, the caller’s code will fail. To avoid this, I could return list.ToArray or make a read-only list before returning it to the caller. But for me this seems to be a big overkill. What do you think?

Please note, I never will return an internally used list so that the caller can change my objects internal state. The question is only about a short living list that is built temporary to hold the return values.

IEnumerable<string> GetAList() {
    List<string> aList = new List<string>();
    aList.Add("a");
    aList.Add("b");
    return aList;
}

IEnumerable<string> GetAList() {
    List<string> aList = new List<string>();
    aList.Add("a");
    aList.Add("b");
    return aList.ToArray<string>();
}

The examples are super-simple and in this case I would work from the beginning on with arrays, but it’s only to show explain the question.

like image 825
HCL Avatar asked Jul 16 '10 10:07

HCL


People also ask

Is it better to return IEnumerable or list?

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

What is the return type of IEnumerable?

IEnumerable interface Returns an enumerator that iterates through the collection.

What is IEnumerable<>?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.


2 Answers

the possibility that the caller casts the resulting Enumerable<T> back into the List<T> and begins to work further with it

Any caller that does that only has themselves to blame if your implementation changes. You promise to return an Enumerable - so long as you continue to do that, you can't be held responsible for problems in callers that assume more than that.

Note also what @Chris mentions - that there may be political issues which at some point require you to maintain backward compatibility even for callers who 'broke the rules' - Raymond Chen (who works for Microsoft on the App Compatibility team) has a blog full of tales of the shenanigans that result when 'this application breaks on OS version x+1' is not an acceptable answer...

like image 83
AakashM Avatar answered Oct 08 '22 10:10

AakashM


No, this is fine.

This is an example of 'polymorphism' at work. Because the caller to the method is only interested in an IEnumerable<string>, the internal workings of the method are free to return whatever class it likes as long as it derives from the IEnumerable<string> interface.

If the caller takes the IEnumerable<string> and casts up to List<string> then they have broken the contract, which only states that an 'IEnumerable<string> will be returned.

like image 30
Dr Herbie Avatar answered Oct 08 '22 11:10

Dr Herbie