Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OK to return an internal List<T> as an IEnumerable<T> or ICollection<T>? [duplicate]

Possible Duplicate:
Collection<T> versus List<T> what should you use on your interfaces?

Consider this method—the returned variable myVar is a List<T>, but the return type of the method MyMethod() is an IEnumerable<T>:

public IEnumerable<T> MyMethod(string stuff)
{
     var myVar = new List<T>();
     //do stuff

     return myVar;
}

Essentially, what I want to know is if returning myVar as a different type is OK.

Specifically, with respect to my situation, the 'do stuff' goes through a DataRow and assigns the items in that DataRow to a list of objects. I also have similar situations with ICollection and IList return types in other places.

The reason I want to return either IEnumerable or ICollection is so that I'm not returning more than needed. But at the same time, this allows the caller to convert the returned value to a List if it needs to do so.

However, it seems weird that my return statement is returning a List, instead of what the method's return type is. Is this normal practice? Is there anything wrong with doing this?

Clarification (in response to the dupe comments):

Just to clarify, what I'm curious about is if it is okay that my return statement in the body is returning a List<T>, but the method header has a return-type of IEnumerable, or possibly ICollection, Collection, etc... Something different than than bodies return statement.

like image 856
RJP Avatar asked Apr 16 '12 22:04

RJP


4 Answers

Not only there's nothing wrong with it, but it's actually good practice: expose only what is strictly necessary. That way, the caller can't rely on the fact that the method will return a List<T>, so if for some reason you need to change the implementation to return something else, you won't break your contract. However the calling code might break if it (incorrectly) made assumptions about what the method actually returns.

like image 142
Thomas Levesque Avatar answered Nov 15 '22 13:11

Thomas Levesque


The reason to return IEnumerable<T> type is so that they caller cannot modify the list (without casting it back to a list). If you notice all(most?) the extension methods take an IEnumerable<T> argument, so that you know that the extension method doesn't modify your list.

Secondly, List<T> inherits from IEnumerable<T>.

Edit: As Thomas explained in a comment that the IEnumerable<T> could be cast back to a List<T> and modified by the caller. If your main goal is to make it Read-Only, you can return the list as myVar.AsReadOnly(). But then the type is ReadOnlyCollection<T>.

like image 40
Chuck Savage Avatar answered Nov 15 '22 13:11

Chuck Savage


There is nothing wrong with it.

Actually returning concrete class is the only way to satisfy "returns interface" requirement.

There could be drawbacks if you let the knowledge of particular classes to sneak in to calling code (List<T> r = (List<T>)MyMethod("ff")). But if you treat result as interface (as you supposed to) it is ok.

like image 45
Alexei Levenkov Avatar answered Nov 15 '22 11:11

Alexei Levenkov


I think this isn't optimal, since it allows the caller to cast to List<T>, which relies on an implementation detail. I'd add some kind of masking, such as Select(x=>x).

A dynamically typed caller might not even notice that you cast your list to IEnumerable<T>. For him it's simply List<T>.

Returning an internal permanent List<T> as IEnumerable<T> would be very wrong, since it allows the caller to mutate internal state of your class. But since you return a new instance of List<T> on every call, that's not used anywhere else, this argument doesn't apply in your example.

like image 45
CodesInChaos Avatar answered Nov 15 '22 11:11

CodesInChaos