Question

What's the preferred container type when returning multiple objects of the same type from a function?

Is it against good practice to return a simple array (like MyType[]), or should you wrap it in some generic container (like ICollection<MyType>)?

Thanks!

Was it helpful?

Solution

Eric Lippert has a good article on this. In case you can't be bothered to read the entire article, the answer is: return the interface.

OTHER TIPS

Return an IEnumerable<T> using a yield return.

I would return an IList<T> as that gives the consumer of your function the greatest flexibility. That way if the consumer of your function only needed to enumerate the sequence they can do so, but if they want to use the sequence as a list they can do that as well.

My general rule of thumb is to accept the least restrictive type as a parameter and return the richest type I can. This is, of course, a balancing act as you don't want to lock yourself into any particular interface or implementation (but always, always try to use an interface).

This is the least presumptuous approach that you, the API developer, can take. It is not up to you to decide how a consumer of your function will use what they send you - that is why you would return an IList<T> in this case as to give them the greatest flexibility. Also for this same reason you would never presume to know what type of parameter a consumer will send you. If you only need to iterate a sequence sent to you as a parameter then make the parameter an IEnumerable<T> rather than a List<T>.


EDIT (monoxide): Since it doesn't look like the question is going to be closed, I just want to add a link from the other question about this: Why arrays are harmful

Why not List<T>?

From the Eric Lippert post mentioned by others, I thought I will highlight this:

If I need a sequence I’ll use IEnumerable<T>, if I need a mapping from contiguous numbers to data I’ll use a List<T>, if I need a mapping across arbitrary data I’ll use a Dictionary<K,V>, if I need a set I’ll use a HashSet<T>. I simply don’t need arrays for anything, so I almost never use them. They don’t solve a problem I have better than the other tools at my disposal.

If the collection that is being returned is read-only, meaning you never want the elements to in the collection to be changed, then use IEnumerable<T>. This is the most basic representation of a read-only sequence of immutable (at least from the perspective of the enumeration itself) elements.

If you want it to be a self-contained collection that can be changed, then use ICollection<T> or IList<T>.

For example, if you wanted to return the results of searching for a particular set of files, then return IEnumerable<FileInfo>.

However, if you wanted to expose the files in a directory, however, you would expose IList/ICollection<FileInfo> as it makes sense that you would want to possibly change the contents of the collection.

A good piece of advice that I've oft heard quoted is this:

Be liberal in what you accept, precise in what you provide.

In terms of designing your API, I'd suggest you should be returning an Interface, not a concrete type.

Taking your example method, I'd rewrite it as follows:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

The key is that your internal implementation choice - to use a List - isn't revealed to the caller, but you're returning an appropriate interface.

Microsoft's own guidelines on framework development recommend against returning specific types, favoring interfaces. (Sorry, I couldn't find a link for this)

Similarly, your parameters should be as general as possible - instead of accepting an array, accept an IEnumerable of the appropriate type. This is compatible with arrays as well as lists and other useful types.

Taking your example method again:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}
return ICollection<type>

The advantage to generic return types, is that you can change the underlying implementation without changing the code that uses it. The advantage to returning the specific type, is you can use more type specific methods.

Always return an interface type that presents the greatest amount of functionality to the caller. So in your case ICollection<YourType> ought to be used.

Something interesting to note is that the BCL developers actually got this wrong in some place of the .NET framework - see this Eric Lippert blog post for that story.

Why not IList<MyType>?

It supports direct indexing which is hallmark for an array without removing the possibility to return a List<MyType> some day. If you want to suppress this feature, you probably want to return IEnumerable<MyType>.

It depends on what you plan to do with the collection you're returning. If you're just iterating, or if you only want the user to iterate, then I agree with @Daniel, return IEnumerable<T>. If you actually want to allow list-based operations, however, I'd return IList<T>.

Use generics. It's easier to interoperate with other collections classes and the type system is more able to help you with potential errors.

The old style of returning an array was a crutch before generics.

What ever makes your code more readable, maintainable and easier for YOU. I would have used the simple array, simpler==better most of the time. Although I really have to see the context to give the right answer.

There are big advantages to favouring IEnumerable over anything else, as this gives you the greatest implementation flexibility and allows you to use yield return or Linq operators for lazy implementation.

If the caller wants a List<T> instead they can simply call ToList() on whatever you returned, and the overall performance will be roughly the same as if you had created and returned a new List<T> from your method.

Array is harmful, but ICollection<T> is also harmful.

ICollection<T> cannot guarantee the object will be immutable.

My recommendation is to wrap the returning object with ReadOnlyCollection<T>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top