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.
No, because the consumer should know what exactly IList is:
IList is a descendant of the ICollection interface and is the base interface of all non-generic lists. IList implementations fall into three categories: read-only, fixed-size, and variable-size. A read-only IList cannot be modified. A fixed-size IList does not allow the addition or removal of elements, but it allows the modification of existing elements. A variable-size IList allows the addition, removal, and modification of elements.
You can check for IList.IsFixedSize
and IList.IsReadOnly
and do what you want with it.
I think IList
is an example of a fat interface and it should have been split into multiple smaller interfaces and it also violates Liskov substitution principle when you return an array as an IList
.
Read more if you want to make decision about returning interface
UPDATE
Digging more and I found that IList<T>
does not implement IList
and IsReadOnly
is accessible through base interface ICollection<T>
but there is no IsFixedSize
for IList<T>
. Read more about why generic IList<> does not inherit non-generic IList?
As with all "interface versus implementation" question, you'll have to realise what exposing a public member means: it defines the public API of this class.
If you expose a List<T>
as a member (field, property, method, ...), you tell the consumer of that member: the type obtained by accessing this method is a List<T>
, or something derived of that.
Now if you expose an interface, you hide the "implementation detail" of your class using a concrete type. Of course you can't instantiate IList<T>
, but you can use an Collection<T>
, List<T>
, derivations thereof or your own type implementing IList<T>
.
The actual question is "Why does Array
implement IList<T>
", or "Why has the IList<T>
interface so many members".
It also depends on what you want the consumers of that member to do. If you actually return an internal member through your Expose...
member, you'll want to return a new List<T>(internalMember)
anyway, as otherwise the consumer can try and cast them to IList<T>
and modify your internal member through that.
If you just expect consumers to iterate the results, expose IEnumerable<T>
or IReadOnlyCollection<T>
instead.