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.
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).
IEnumerable interface Returns an enumerator that iterates through the collection.
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.
the possibility that the caller casts the resulting
Enumerable<T>
back into theList<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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With