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 ofIList
, it is ok to call the method using both the array and theList
:
Indeed, because if the behavioural contract just says "I can output int
s", 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
Splitting a String into Chunks of a Certain Size
How to Apply an Xslt Stylesheet in C#
Is Polymorphic Deserialization Possible in System.Text.Json
String Output: Format or Concat in C#
Passing Arguments to C# Generic New() of Templated Type
Delete a File Being Used by Another Process
What Is the 'Dynamic' Type in C# 4.0 Used For
How to Convert Image to Byte Array
Get the Correct Week Number of a Given Date
Why Must "Stride" in the System.Drawing.Bitmap Constructor Be a Multiple of 4
How to Dynamically Create Generic C# Object Using Reflection
Convert Json String to C# Object
How to Retrieve Id of Inserted Entity Using Entity Framework
Using C#, How Does One Figure Out What Process Locked a File