Returning 'IList' vs 'ICollection' vs 'Collection'

C#.NetGenericsCollections

C# Problem Overview


I am confused about which collection type that I should return from my public API methods and properties.

The collections that I have in mind are IList, ICollection and Collection.

Is returning one of these types always preferred over the others, or does it depend on the specific situation?

C# Solutions


Solution 1 - C#

ICollection<T> is an interface that exposes collection semantics such as Add(), Remove(), and Count.

Collection<T> is a concrete implementation of the ICollection<T> interface.

IList<T> is essentially an ICollection<T> with random order-based access.

In this case you should decide whether or not your results require list semantics such as order based indexing (then use IList<T>) or whether you just need to return an unordered "bag" of results (then use ICollection<T>).

Solution 2 - C#

Generally you should return a type that is as general as possible, i.e. one that knows just enough of the returned data that the consumer needs to use. That way you have greater freedom to change the implementation of the API, without breaking the code that is using it.

Consider also the IEnumerable<T> interface as return type. If the result is only going to be iterated, the consumer doesn't need more than that.

Solution 3 - C#

The main difference between the IList<T> and ICollection<T> interfaces is that IList<T> allows you to access elements via an index. IList<T> describes array-like types. Elements in an ICollection<T> can only be accessed through enumeration. Both allow the insertion and deletion of elements.

If you only need to enumerate a collection, then IEnumerable<T> is to be preferred. It has two advantages over the others:

  1. It disallows changes to the collection (but not to the elements, if they are of reference type).

  2. It allows the largest possible variety of sources, including enumerations that are generated algorithmically and are not collections at all.

  3. Allows lazy evaluation and can be queried with LINQ.

Collection<T> is a base class that is mainly useful to implementers of collections. If you expose it in interfaces (APIs), many useful collections not deriving from it will be excluded.


One disadvantage of IList<T> is that arrays implement it but do not allow you to add or remove items (i.e. you cannot change the array length). An exception will be thrown if you call IList<T>.Add(item) on an array. The situation is somewhat defused as IList<T> has a Boolean property IsReadOnly that you can check before attempting to do so. But in my eyes, this is still a design flaw in the library. Therefore, I use List<T> directly, when the possibility to add or remove items is required.


Which one should I choose? Let's consider just List<T> and IEnumerable<T> as examples for specialized / generalized types:

  • Method input parameter
    • IEnumerable<T> greatest flexibility for the caller. Restrictive for the implementer, read-only.
    • List<T> Restrictive for the caller. Gives flexibility to the implementer, can manipulate the collection.
  • Method ouput parameter or return value
    • IEnumerable<T> Restrictive for the caller, read-only. Greatest flexibility for the implementer. Allows to return about any collection or to implement an iterator (yield return).
    • List<T> Greatest flexibility for the caller, can manipulate the returned collection. Restrictive for the implementer.

Well, at this point you may be disappointed because I don't give you a simple answer. A statement like "always use this for input and that for output" would not be constructive. The reality is that it depends on use case. A method like void AddMissingEntries(TColl collection) will have to provide a collection type having an Add method or may even require a HashSet<T> for efficiency. A method void PrintItems(TColl collection) can happily live with an IEnumerable<T>.

Solution 4 - C#

IList<T> is the base interface for all generic lists. Since it is an ordered collection, the implementation can decide on the ordering, ranging from sorted order to insertion order. Moreover Ilist has Item property that allows methods to read and edit entries in the list based on their index. This makes it possible to insert, remove a value into/from the list at a position index.

Also since IList<T> : ICollection<T>, all the methods from ICollection<T> are also available here for implementation.

ICollection<T> is the base interface for all generic collections. It defines size, enumerators and synchronization methods. You can add or remove an item into a collection but you cannot choose at which position it happens due to the absence of index property.

Collection<T> provides an implementation for IList<T>, IList and IReadOnlyList<T>.

If you use a narrower interface type such as ICollection<T> instead of IList<T>, you protect your code against breaking changes. If you use a wider interface type such as IList<T>, you are more in danger of breaking code changes.

Quoting from a source,

> ICollection, ICollection<T> : You want to modify the collection or > you care about its size. IList, IList<T>: You want to modify the collection and you care about the ordering and / or positioning of the elements in the collection.

Solution 5 - C#

Returning an interface type is more general, so (lacking further information on your specific use case) I'd lean towards that. If you want to expose indexing support, choose IList<T>, otherwise ICollection<T> will suffice. Finally, if you want to indicate that the returned types are read only, choose IEnumerable<T>.

And, in case you haven't read it before, Brad Abrams and Krzysztof Cwalina wrote a great book titled "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" (you can download a digest from here).

Solution 6 - C#

There are some subjects that come from this question:

  • interfaces versus classes
  • which specific class, from several alike classes, collection, list, array ?
  • Common classes versus subitem ("generics") collections

You may want to highlight that its an Object Oriented A.P.I.

interfaces versus classes

If you don't have much experience with interfaces, I recommend stick to classes. I see a lot of times of developers jumping to interfaces, even if its not necesarilly.

And, end doing a poor interface design, instead of, a good class design, which, by the way, can eventually, be migrated to a good interface design ...

You'll see a lot of interfaces in A.P.I., but, don't rush to it, if you don't need it.

You will eventually learn how to apply interfaces, to your code.

which specific class, from several alike classes, collection, list, array ?

There are several classes in c# (dotnet) that can be interchanged. As already mention, if you need something from a more specific class, such as "CanBeSortedClass", then make it explicit in your A.P.I..

Does your A.P.I. user really needs to know, that your class can be sorted, or apply some format to the elements ? Then use "CanBeSortedClass" or "ElementsCanBePaintedClass", otherwise use "GenericBrandClass".

Otherwise, use a more general class.

Common collection classes versus subitem ("generics") collections

You'll find that there are classes that contains others elements, and you can specify that all elements should be of an specific type.

Generic Collections are those classes that you can use the same collection, for several code applications, without having to create a new collection, for each new subitem type, like this: Collection.

Does your A.P.I. user is going to need a very specific type, same for all elements ?

Use something like List<WashingtonApple> .

Does your A.P.I. user is going to need several related types ?

Expose List<Fruit> for your A.P.I., and use List<Orange> List<Banana>, List<Strawberry> internally, where Orange, Banana and Strawberry are descendants from Fruit .

Does your A.P.I. user is going to need a generic type collection ?

Use List, where all items are object (s).

Cheers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRocky SinghView Question on Stackoverflow
Solution 1 - C#cordialgermView Answer on Stackoverflow
Solution 2 - C#GuffaView Answer on Stackoverflow
Solution 3 - C#Olivier Jacot-DescombesView Answer on Stackoverflow
Solution 4 - C#NullReferenceView Answer on Stackoverflow
Solution 5 - C#AlanView Answer on Stackoverflow
Solution 6 - C#umlcatView Answer on Stackoverflow