List≪T≫ or Ilist≪T≫

List T or IList T

If you are exposing your class through a library that others will use, you generally want to expose it via interfaces rather than concrete implementations. This will help if you decide to change the implementation of your class later to use a different concrete class. In that case the users of your library won't need to update their code since the interface doesn't change.

If you are just using it internally, you may not care so much, and using List<T> may be ok.

Why should I return IList T over List T ?

The reason is so that your method can be used with anything that implements IList<T>, and not just a List. It gets even worse, though, since the advent of Linq, I've started making a lot of stuff return Enumerable<T> or even just IEnumerable!

I am not sure I understand the difficulty, though. If something is returning an actual list, and its return depends on that, or its use is specific to that, then it should return List<T>. If not, then you should have no need to cast it to a List.

Is returning IList T worse than returning T[] or List T ?

Maybe this is not directly answering your question, but in .NET 4.5+, I prefer to follow these rules when designing public or protected APIs:

  • do return IEnumerable<T>, if only enumeration is available;
  • do return IReadOnlyCollection<T> if both enumeration and items count are available;
  • do return IReadOnlyList<T>, if enumeration, items count and indexed access are available;
  • do return ICollection<T> if enumeration, items count and modification are available;
  • do return IList<T>, if enumeration, items count, indexed access and modification are available.

Last two options assume, that method must not return array as IList<T> implementation.

What is difference between IList and IList T

The reason that List<T> implements both IList<T> and IList is to make it usable anywhere your code is assuming an IList. This will make it more easier to make a transition to the generic IList<T> since it is the more appropriate one. Also, if you have a .net 1.1 or earlier code that you would like to reuse even though your class is implemented in a .net 2.0 or later assembly it will make it possible.

When to use IList and when to use List

There are two rules I follow:

  • Accept the most basic type that will work
  • Return the richest type your user will need

So when writing a function or method that takes a collection, write it not to take a List, but an IList<T>, an ICollection<T>, or IEnumerable<T>. The generic interfaces will still work even for heterogenous lists because System.Object can be a T too. Doing this will save you headache if you decide to use a Stack or some other data structure further down the road. If all you need to do in the function is foreach through it, IEnumerable<T> is really all you should be asking for.

On the other hand, when returning an object out of a function, you want to give the user the richest possible set of operations without them having to cast around. So in that case, if it's a List<T> internally, return a copy as a List<T>.

How can a C# List IList accept a List T but not an IList T when creating the collection?

IList<T> implements the following interfaces: ICollection<T>, IEnumerable<T>, and IEnumerable.

List<T> implements the following interfaces IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, and IReadOnlyCollection<T>.

So an IList<T> cannot be cast to an IList, but a List<T> can.

Generic list of lists, converting List List T to IList IList T

Suppose we have a method

void Bar(IList<IList<int>> foo)

Within Bar, it should then be perfectly admissible to add a int[] to foo - after all, int[] implements IList<int>, doesn't it?

But if we had called Bar with a List<List<int>>, we would now be trying to add a int[] to something that only accepts a List<int>! which would be bad. So the compiler doesn't let you do this.

Also, while testing different solutions to the problem, I found out that if the class library method had been declared with IEnumerable instead of IList, it is ok to call the method using both the array and the List:

Indeed, because if the behavioural contract just says "I can output ints", nothing can go wrong. The key terms for further research are covariance and contravariance, and no one* can ever remember which is which.

In your particular case, if Calculate is only ever reading its input, changing it to consume IEnumerable is absolutely the right thing to do - it both allows you to pass in any qualifying objects, and it further communicates to anyone reading the signature that this method is intentionally designed to only consume, not mutate, its input.


* well, mostly no one



Related Topics



Leave a reply



Submit