Update: I appreciate all of the comments, which have essentially comprised unanimous opposition. While every objection raised was valid, I feel that the ultimate nail in the coffin was Ani's astute observation that, ultimately, even the one miniscule benefit that this idea ostensibly offered -- the elimination of boilerplate code -- was negated by the fact that the idea itself would require its own boilerplate code.
So yeah, consider me convinced: it would be a bad idea.
And just to sort of salvage my dignity somewhat: I might have played it up for argument's sake, but I was never really sold on this idea to begin with -- merely curious to hear what others had to say about it. Honest.
Before you dismiss this question as absurd, I ask you to consider the following:
IEnumerable<T> inherits from* IEnumerable, which means that any type that implements IEnumerable<T> generally must implement both IEnumerable<T>.GetEnumerator and (explicitly) IEnumerable.GetEnumerator. This basically amounts to boilerplate code.
You can foreach over any type that has a GetEnumerator method, as long as that method returns an object of some type with a MoveNext method and a Current property. So if your type defines one method with the signature public IEnumerator<T> GetEnumerator(), it's legal to enumerate over it using foreach.
Clearly, there is a lot of code out there that requires the IEnumerable<T> interface -- for instance, basically all of the LINQ extension methods. Luckily, to go from a type that you can foreach on to an IEnumerable<T> is trivial using the automatic iterator generation that C# supplies via the yield keyword.
So, putting this all together, I had this crazy idea: what if I just define my own interface that looks like this:
public interface IForEachable<T>
{
IEnumerator<T> GetEnumerator();
}
Then whenever I define a type that I want to be enumerable, I implement this interface instead of IEnumerable<T>, eliminating the need to implement two GetEnumerator methods (one explicit). For example:
class NaturalNumbers : IForEachable<int>
{
public IEnumerator<int> GetEnumerator()
{
int i = 1;
while (i < int.MaxValue)
{
yield return (i++);
}
}
// Notice how I don't have to define a method like
// IEnumerator IEnumerable.GetEnumerator().
}
Finally, in order to make this type compatible with code that does expect the IEnumerable<T> interface, I can just define an extension method to go from any IForEachable<T> to an IEnumerable<T> like so:
public static class ForEachableExtensions
{
public static IEnumerable<T> AsEnumerable<T>(this IForEachable<T> source)
{
foreach (T item in source)
{
yield return item;
}
}
}
It seems to me that doing this enables me to design types that are usable in every way as implementations of IEnumerable<T>, but without that pesky explicit IEnumerable.GetEnumerator implementation in each one.
For example:
var numbers = new NaturalNumbers();
// I can foreach myself...
foreach (int x in numbers)
{
if (x > 100)
break;
if (x % 2 != 0)
continue;
Console.WriteLine(x);
}
// Or I can treat this object as an IEnumerable<T> implementation
// if I want to...
var evenNumbers = from x in numbers.AsEnumerable()
where x % 2 == 0
select x;
foreach (int x in evenNumbers.TakeWhile(i => i <= 100))
{
Console.WriteLine(x);
}
What do you guys think of this idea? Am I missing some reason why this would be a mistake?
I realize it probably seems like an overly complex solution to what isn't that big of a deal to start with (I doubt anybody really cares that much about having to explicitly define the IEnumerable interface); but it just popped into my head and I'm not seeing any obvious problems that this approach would pose.
In general, if I can write a moderate amount of code once to save myself the trouble of having to write a small amount of code lots of times, to me, it's worth it.
*Is that the right terminology to use? I'm always hesitant to say one interface "inherits from" another, as that doesn't seem to properly capture the relationship between them. But maybe it's right on.
You're missing one huge thing -
If you implement your own interface instead of IEnumerable<T>, your class will not work with the framework methods expecting IEnumerable<T> - mainly, you will be completely unable to use LINQ, or use your class to construct a List<T>, or many other useful abstractions.
You can accomplish this, as you mention, via a separate extension method - however, this comes at a cost. By using an extension method to convert to an IEnumerable<T>, you're adding another level of abstraction required in order to use your class (which you'll do FAR more often than authoring the class), and you decrease performance (your extension method will, in effect, generate a new class implementation internally, which is really unnecessary). Most importantly, any other user of your class (or you later) will have to learn a new API that accomplishes nothing - you're making your class more difficult to use by not using standard interfaces, since it violates the user's expectations.
You're right: it does seem an overly complex solution to a pretty easy problem.
It also introduces an extra level of indirection for every step of the iteration. Probably not a performance problem, but still somewhat unnecessary when I don't think you're really gaining anything very significant.
Also, although your extension method lets you convert any IForEachable<T> into an IEnumerable<T>, it means your type itself won't satisfy a generic constraint like this:
public void Foo<T>(T collection) where T : IEnumerable
or the like. Basically, by having to perform your conversion, you're losing the ability to treat a single object as both an implementation of IEnumerable<T> and the real concrete type.
Also, by not implementing IEnumerable, you're counting yourself out of collection initializers. (I sometimes implement IEnumerable explicitly just to opt into collection initialization, throwing an exception from GetEnumerator().)
Oh, and you've also introduced an extra bit of infrastructure which is unfamiliar to everyone else in the world, compared with the vast hordes of C# developers who already know about IEnumerable<T>.
Aren't you just moving the boilerplate somewhere else - from writing the IEnumerable.GetEnumeratormethod on each class to calling your AsEnumerable extension every time an IEnumerable<T> is expected? Typically, I would expect an enumerable type to be used for querying far more times than it is written (which is exactly once). This would mean that this pattern will lead to more boilerplate, on average.
In our codebase there's probably more than 100 instances of this exact snippet:
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
And I am really OK with that. It's a tiny price to pay for full compatibility with every other piece of .NET code ever written ;)
Your proposed solution essentially requires every consumer/caller of your new interface to also remember to call a special extension method on it before it is useful.
It is so much easier to use IEnumerable for reflection. Trying to invoke generic interfaces via reflection is such a pain. The penalty of boxing via IEnumerable is lost by the overhead of reflection itself so why bother using a generic interface? As for an example, serialization comes to mind.
I think everyone has already mentioned the technical reasons not to do this, so I'll add this into the mix: requiring your user to call AsEnumerable() on your collection to be able to use enumerable extensions would violate the principle of least surprise.
Related
I've seen similar questions but I'm still lost in regards to the return type of Public, Internal and Private methods. When should my return type by Collection and when should it be IEnumerable
The MSDN guide says
X DO NOT use weakly typed collections in public APIs.
The type of all return values and parameters representing collection items should be the exact item type, not any of its base types (this applies only to public members of the collection).
This has totally confused me and implies that everything (public) should be Collection<T> or ReadOnlyCollection<T>. My confusion comes in when can we use List<T>, for example
public Collection<string> DoThisThing(int i)
{
Collection<string> col = new Collection<string>();
List<string> myList = null;
if (i > 0)
myList = GetListOfString();
//col.AddRange(...); Can't AddRange as no method
//return myList; Can't do this as it expects return type of Collection<string>
//So, to ensure my return is Collection, I have to convert
foreach(var item in myList)
{
col.Add(item);
}
return col;
}
In the above example, it's perfectly valid that List is a better choice, so, if I want to use AddRange, I could either
Hope to have control of API so I can change the return type of GetListOfString to Collection (not always possible)
Add an extension method to Control to support AddRange
Type it out every time, as I do above
However, if I do option 1, then I don't see when I'd ever actually use ToList() (other than when I have to if an external API returns List) as all my return types would be either Collection<T>, ReadOnlyCollection<T>
Using option 2 seems more sensible but, now I'm lost as it feels as if I'm forcing it to do something it isn't intended to do.
Option 3 is repetitive
Whist I appreciate it will always depend on the situation, as a general rule, is the following accurate
Public - Should be very precise, for example IEnumerable<string> (note, not T), but not Collection<T>/Collection<string>
Internal and private - Should be more agnostic, so Collection<T> is better (and live with not really using List or if I do have to use, I will have to cast it into Collection<T>
EDIT: added code at the end
You are confusing several different layers of the guide.
In your internal code you are free to do what you like, albeit there are guidelines for how to write code that is clean, readable and easy to maitain. Still, those are implementation details and they are tucked away behind your public methods, so you can do what you want (you may shoot in your own foot).
Artifacts you write to be used by other developers are one of these:
libraries;
frameworks;
modules of "some kind".
Now, in these cases you must decide:
the boundaries of your artifact;
how those developers use your artifact.
The boundaries are well defined by an assembly, if you choose to have one.
Sometimes namespaces may be considered "internal boundaries" and the consumer is yourself, in the future. Organizing your code into internal boundaries is a good practice but consider that classes already define boundaries so don't overdo it. Group 10-20 classes in a namespace by cohesion and keep those groups apart without interdependencies by low coupling. You cannot really understand what I mean here when I say bridge... but come back in a year or so and read this answer again :)
How to use the assembly is defined in these places:
manifest (generated automatically by the VS packaging);
documentation (which should accompany your assembly);
source code (if you expose it);
public constructs (enums, interfaces, classes, namespaces, package dependencies);
public and protected methods.
Now with all those tools you have a way to design that thing called an API.
There is plenty of room to maneuver and make mistakes. Because of this, the good people at M$ decided to define a uniform and consistent way of designing the default APIs in the default assemblies and namespaces (such as System.*).
What you have touched in your question is a guideline to API designers (which you might or might not be). All they say is:
if you are designing an API such as a non-internal method of a public class in an accessible assembly, than do us the favor and return a tightly defined value, as concrete as possible.
So, if it is a List<T> don't return any of the ancestors such as IEnumerable<T> or whatever. This allows the consumers (other developers) of your assembly to leverage concrete properties of your return value.
On the other hand you should accept as general values as possible. If you just use a method of IEnumerable<T> in your method you should require just that:
public void MyMethod<T>(IEnumerable<T> e);
This signature of your method allows consumers to pass in many different concrete collections. The only thing you require is that it is (derives from) an IEnumerable<T>.
These design decisions are also bound to many important OO principles of SOLID. They postulate that:
you should depend on abstractions => so expose interfaces if possible and keep your API abstract;
you should hide implementation details so that changes in your assembly don't propagate to consumer code;
you should avoid changing the API by allowing extension mechanism.
To be more precise I take your code and try to be as concrete as possible:
public List<string> DoThisThing(int i) // use list to return a more concrete type
{
List<string> list = new List<string>(); // you really want a *LIST* so why be abstract in your own code innards?
// List<string> myList = null; <-- superfluous
if (i > 0)
{
list = GetListOfString();
} // ALWAYS (!) use code blocks, see the book "Clean Code"
// this problem is solved: in your internal code don't be abstract if you don't need it
//col.AddRange(...); Can't AddRange as no method
return list; // Can't do this as it expects return type of Collection<string>
// you're done...
// So, to ensure my return is Collection, I have to convert
// foreach(var item in myList)
// {
// col.Add(item);
// }
// return col;
}
Some help about the theory behind all this: The SOLID principles.
What you really want to understand is how and why you need abstractions. When you really grasp that, you will also understand when you DO NOT need them and so decide in a reasoned manner when to use IEnumerable<T> or List<string> without negative repercussions on the rest of your code. The most important principles of SOLID are in this case OCP and DIP.
Your question seems to be thinking into the "wrong" direction, starting from the initial MSDN quotation:
X DO NOT use weakly typed collections in public APIs.
The type of all return values and parameters representing collection items should be the exact item type, not any of its base types (this applies only to public members of the collection).
This refers to the items of collections, not the collection types.
This guideline does not refer to the type of the collection itself at all. Whether you return an enumerable, a collection, a list, or any other collection type, entirely depends on how you intend your collection to behave and what guarantees you want to make about the set of items you store.
The guideline you cited, on the other hand, indicates that you should strongly type the items stored in your collection. That is, if you have a list of string values, do not declare the collection item type as object (e.g. by typing the collection to IEnumerable<object> or IList<object>), but do use string as the item type (e.g. IEnumerable<string>, ICollection<string>, IList<string>).
I have spent quite a few hours pondering the subject of exposing list members. In a similar question to mine, Jon Skeet gave an excellent answer. Please feel free to have a look.
ReadOnlyCollection or IEnumerable for exposing member collections?
I am usually quite paranoid to exposing lists, especially if you are developing an API.
I have always used IEnumerable for exposing lists, as it is quite safe, and it gives that much flexibility. Let me use an example here:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IEnumerable<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
Anyone who codes against an IEnumerable is quite safe here. If I later decide to use an ordered list or something, none of their code breaks and it is still nice. The downside of this is IEnumerable can be cast back to a list outside of this class.
For this reason, a lot of developers use ReadOnlyCollection for exposing a member. This is quite safe since it can never be cast back to a list. For me I prefer IEnumerable since it provides more flexibility, should I ever want to implement something different than a list.
I have come up with a new idea I like better. Using IReadOnlyCollection:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return new ReadOnlyCollection<WorkItem>(this.workItems);
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
I feel this retains some of the flexibility of IEnumerable and is encapsulated quite nicely.
I posted this question to get some input on my idea. Do you prefer this solution to IEnumerable? Do you think it is better to use a concrete return value of ReadOnlyCollection? This is quite a debate and I want to try and see what are the advantages/disadvantages that we all can come up with.
EDIT
First of all thank you all for contributing so much to the discussion here. I have certainly learned a ton from each and every one and would like to thank you sincerely.
I am adding some extra scenarios and info.
There are some common pitfalls with IReadOnlyCollection and IEnumerable.
Consider the example below:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
The above example can be casted back to a list and mutated, even though the interface is readonly. The interface, despite it's namesake does not guarantee immutability. It is up to you to provide an immutable solution, therefore you should return a new ReadOnlyCollection. By creating a new list (a copy essentially), the state of your object is safe and sound.
Richiban says it best in his comment: a interface only guarantees what something can do, not what it cannot do.
See below for an example:
public IEnumerable<WorkItem> WorkItems
{
get
{
return new List<WorkItem>(this.workItems);
}
}
The above can be casted and mutated, but your object is still immutable.
Another outside the box statement would be collection classes. Consider the following:
public class Bar : IEnumerable<string>
{
private List<string> foo;
public Bar()
{
this.foo = new List<string> { "123", "456" };
}
public IEnumerator<string> GetEnumerator()
{
return this.foo.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
The class above can have methods for mutating foo the way you want it to be, but your object can never be casted to a list of any sort and mutated.
Carsten Führmann makes a fantastic point about yield return statements in IEnumerables.
One important aspect seems to be missing from the answers so far:
When an IEnumerable<T> is returned to the caller, they must consider the possibility that the returned object is a "lazy stream", e.g. a collection built with "yield return". That is, the performance penalty for producing the elements of the IEnumerable<T> may have to be paid by the caller, for each use of the IEnumerable. (The productivity tool "Resharper" actually points this out as a code smell.)
By contrast, an IReadOnlyCollection<T> signals to the caller that there will be no lazy evaluation. (The Count property, as opposed to the Count extension method of IEnumerable<T> (which is inherited by IReadOnlyCollection<T> so it has the method as well), signals non-lazyness. And so does the fact that there seem to be no lazy implementations of IReadOnlyCollection.)
This is also valid for input parameters, as requesting an IReadOnlyCollection<T> instead of IEnumerable<T> signals that the method needs to iterate several times over the collection. Sure the method could create its own list from the IEnumerable<T> and iterate over that, but as the caller may already have a loaded collection at hand it would make sense to take advantage of it whenever possible. If the caller only has an IEnumerable<T> at hand, he only needs to add .ToArray() or .ToList() to the parameter.
What IReadOnlyCollection does not do is prevent the caller to cast to some other collection type. For such protection, one would have to use the class ReadOnlyCollection<T>.
In summary, the only thing IReadOnlyCollection<T> does relative to IEnumerable<T> is add a Count property and thus signal that no lazyness is involved.
Talking about class libraries, I think IReadOnly* is really useful, and I think you're doing it right :)
It's all about immutable collection... Before there were just immutables and to enlarge arrays was a huge task, so .net decided to include in the framework something different, mutable collection, that implement the ugly stuff for you, but IMHO they didn't give you a proper direction for immutable that are extremely useful, especially in a high concurrency scenario where sharing mutable stuff is always a PITA.
If you check other today languages, such as objective-c, you will see that in fact the rules are completely inverted! They quite always exchange immutable collection between different classes, in other words the interface expose just immutable, and internally they use mutable collection (yes, they have it of course), instead they expose proper methods if they want let the outsiders change the collection (if the class is a stateful class).
So this little experience that I've got with other languages pushes me to think that .net list are so powerful, but the immutable collection were there for some reason :)
In this case is not a matter of helping the caller of an interface, to avoid him to change all the code if you're changing internal implementation, like it is with IList vs List, but with IReadOnly* you're protecting yourself, your class, to being used in not a proper way, to avoid useless protection code, code that sometimes you couldn't also write (in the past in some piece of code I had to return a clone of the complete list to avoid this problem).
My take on concerns of casting and IReadOnly* contracts, and 'proper' usages of such.
If some code is being “clever” enough to perform an explicit cast and break the interface contract, then it is also “clever” enough to use reflection or otherwise do nefarious things such as access the underlying List of a ReadOnlyCollection wrapper object. I don’t program against such “clever” programmers.
The only thing that I guarantee is that after said IReadOnly*-interface objects are exposed, then my code will not violate that contract and will not modified the returned collection object.
This means that I write code that returns List-as-IReadOnly*, eg., and rarely opt for an actual read-only concrete type or wrapper. Using IEnumerable.ToList is sufficient to return an IReadOnly[List|Collection] - calling List.AsReadOnly adds little value against “clever” programmers who can still access the underlying list that the ReadOnlyCollection wraps.
In all cases, I guarantee that the concrete types of IReadOnly* return values are eager. If I ever write a method that returns an IEnumerable, it is specifically because the contract of the method is that which “supports streaming” fsvo.
As far as IReadOnlyList and IReadOnlyCollection, I use the former when there is 'an' implied stable ordering established that is meaningful to index, regardless of purposeful sorting. For example, arrays and Lists can be returned as an IReadOnlyList while a HashSet would better be returned as an IReadOnlyCollection. The caller can always assign the I[ReadOnly]List to an I[ReadOnly]Collection as desired: this choice is about the contract exposed and not what a programmer, “clever” or otherwise, will do.
It seems that you can just return an appropriate interface:
...
private readonly List<WorkItem> workItems = new List<WorkItem>();
// Usually, there's no need the property to be virtual
public virtual IReadOnlyList<WorkItem> WorkItems {
get {
return workItems;
}
}
...
Since workItems field is in fact List<T> so the natural idea IMHO is to expose the most wide interface which is IReadOnlyList<T> in the case
!! IEnumerable vs IReadOnlyList !!
IEnumerable has been with us from the beginning of time. For many years, it was a de facto standard way to represent a read-only collection. Since .NET 4.5, however, there is another way to do that: IReadOnlyList.
Both collection interfaces are useful.
<>
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Can anyone explain to me why I would want to use IList over List in C#?
Related question: Why is it considered bad to expose List<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.
The less popular answer is programmers like to pretend their software is going to be re-used the world over, when infact the majority of projects will be maintained by a small amount of people and however nice interface-related soundbites are, you're deluding yourself.
Architecture Astronauts. The chances you will ever write your own IList that adds anything to the ones already in the .NET framework are so remote that it's theoretical jelly tots reserved for "best practices".
Obviously if you are being asked which you use in an interview, you say IList, smile, and both look pleased at yourselves for being so clever. Or for a public facing API, IList. Hopefully you get my point.
Interface is a promise (or a contract).
As it is always with the promises - smaller the better.
Some people say "always use IList<T> instead of List<T>".
They want you to change your method signatures from void Foo(List<T> input) to void Foo(IList<T> input).
These people are wrong.
It's more nuanced than that. If you are returning an IList<T> as part of the public interface to your library, you leave yourself interesting options to perhaps make a custom list in the future. You may not ever need that option, but it's an argument. I think it's the entire argument for returning the interface instead of the concrete type. It's worth mentioning, but in this case it has a serious flaw.
As a minor counterargument, you may find every single caller needs a List<T> anyway, and the calling code is littered with .ToList()
But far more importantly, if you are accepting an IList as a parameter you'd better be careful, because IList<T> and List<T> do not behave the same way. Despite the similarity in name, and despite sharing an interface they do not expose the same contract.
Suppose you have this method:
public Foo(List<int> a)
{
a.Add(someNumber);
}
A helpful colleague "refactors" the method to accept IList<int>.
Your code is now broken, because int[] implements IList<int>, but is of fixed size. The contract for ICollection<T> (the base of IList<T>) requires the code that uses it to check the IsReadOnly flag before attempting to add or remove items from the collection. The contract for List<T> does not.
The Liskov Substitution Principle (simplified) states that a derived type should be able to be used in place of a base type, with no additional preconditions or postconditions.
This feels like it breaks the Liskov substitution principle.
int[] array = new[] {1, 2, 3};
IList<int> ilist = array;
ilist.Add(4); // throws System.NotSupportedException
ilist.Insert(0, 0); // throws System.NotSupportedException
ilist.Remove(3); // throws System.NotSupportedException
ilist.RemoveAt(0); // throws System.NotSupportedException
But it doesn't. The answer to this is that the example used IList<T>/ICollection<T> wrong. If you use an ICollection<T> you need to check the IsReadOnly flag.
if (!ilist.IsReadOnly)
{
ilist.Add(4);
ilist.Insert(0, 0);
ilist.Remove(3);
ilist.RemoveAt(0);
}
else
{
// what were you planning to do if you were given a read only list anyway?
}
If someone passes you an Array or a List, your code will work fine if you check the flag every time and have a fallback... But really; who does that? Don't you know in advance if your method needs a list that can take additional members; don't you specify that in the method signature? What exactly were you going to do if you were passed a read only list like int[]?
You can substitute a List<T> into code that uses IList<T>/ICollection<T> correctly. You cannot guarantee that you can substitute an IList<T>/ICollection<T> into code that uses List<T>.
There's an appeal to the Single Responsibility Principle / Interface Segregation Principle in a lot of the arguments to use abstractions instead of concrete types - depend on the narrowest possible interface. In most cases, if you are using a List<T> and you think you could use a narrower interface instead - why not IEnumerable<T>? This is often a better fit if you don't need to add items. If you need to add to the collection, use the concrete type, List<T>.
For me IList<T> (and ICollection<T>) is the worst part of the .NET framework. IsReadOnly violates the principle of least surprise. A class, such as Array, which never allows adding, inserting or removing items should not implement an interface with Add, Insert and Remove methods. (see also https://softwareengineering.stackexchange.com/questions/306105/implementing-an-interface-when-you-dont-need-one-of-the-properties)
Is IList<T> a good fit for your organisation? If a colleague asks you to change a method signature to use IList<T> instead of List<T>, ask them how they'd add an element to an IList<T>. If they don't know about IsReadOnly (and most people don't), then don't use IList<T>. Ever.
Note that the IsReadOnly flag comes from ICollection<T>, and indicates whether items can be added or removed from the collection; but just to really confuse things, it does not indicate whether they can be replaced, which in the case of Arrays (which return IsReadOnlys == true) can be.
For more on IsReadOnly, see msdn definition of ICollection<T>.IsReadOnly
List<T> is a specific implementation of IList<T>, which is a container that can be addressed the same way as a linear array T[] using an integer index. When you specify IList<T> as the type of the method's argument, you only specify that you need certain capabilities of the container.
For example, the interface specification does not enforce a specific data structure to be used. The implementation of List<T> happens to the same performance for accessing, deleting and adding elements as a linear array. However, you could imagine an implementation that is backed by a linked list instead, for which adding elements to the end is cheaper (constant-time) but random-access much more expensive. (Note that the .NET LinkedList<T> does not implement IList<T>.)
This example also tells you that there may be situations when you need to specify the implementation, not the interface, in the argument list: In this example, whenever you require a particular access performance characteristic. This is usually guaranteed for a specific implementation of a container (List<T> documentation: "It implements the IList<T> generic interface using an array whose size is dynamically increased as required.").
Additionally, you might want to consider exposing the least functionality you need. For example. if you don't need to change the content of the list, you should probably consider using IEnumerable<T>, which IList<T> extends.
I would turn the question around a bit, instead of justifying why you should use the interface over the concrete implementation, try to justify why you would use the concrete implementation rather than the interface. If you can't justify it, use the interface.
IList<T> is an interface so you can inherit another class and still implement IList<T> while inheriting List<T> prevents you to do so.
For example if there is a class A and your class B inherits it then you can't use List<T>
class A : B, IList<T> { ... }
public void Foo(IList<Bar> list)
{
// Do Something with the list here.
}
In this case you could pass in any class which implements the IList<Bar> interface. If you used List<Bar> instead, only a List<Bar> instance could be passed in.
The IList<Bar> way is more loosely coupled than the List<Bar> way.
A principle of TDD and OOP generally is programming to an interface not an implementation.
In this specific case since you're essentially talking about a language construct, not a custom one it generally won't matter, but say for example that you found List didn't support something you needed. If you had used IList in the rest of the app you could extend List with your own custom class and still be able to pass that around without refactoring.
The cost to do this is minimal, why not save yourself the headache later? It's what the interface principle is all about.
The most important case for using interfaces over implementations is in the parameters to your API. If your API takes a List parameter, then anyone who uses it has to use List. If the parameter type is IList, then the caller has much more freedom, and can use classes you never heard about, which may not even have existed when your code was written.
Supprising that none of these List vs IList questions (or answers) mentions the signature difference. (Which is why I searched for this question on SO!)
So here's the methods contained by List that are not found in IList, at least as of .NET 4.5 (circa 2015)
AddRange
AsReadOnly
BinarySearch
Capacity
ConvertAll
Exists
Find
FindAll
FindIndex
FindLast
FindLastIndex
ForEach
GetRange
InsertRange
LastIndexOf
RemoveAll
RemoveRange
Reverse
Sort
ToArray
TrimExcess
TrueForAll
What if .NET 5.0 replaces System.Collections.Generic.List<T> to System.Collection.Generics.LinearList<T>. .NET always owns the name List<T> but they guarantee that IList<T> is a contract. So IMHO we (atleast I) are not supposed to use someone's name (though it is .NET in this case) and get into trouble later.
In case of using IList<T>, the caller is always guareented things to work, and the implementer is free to change the underlying collection to any alternative concrete implementation of IList
All concepts are basically stated in most of the answers above regarding why use interface over concrete implementations.
IList<T> defines those methods (not including extension methods)
IList<T> MSDN link
Add
Clear
Contains
CopyTo
GetEnumerator
IndexOf
Insert
Remove
RemoveAt
List<T> implements those nine methods (not including extension methods), on top of that it has about 41 public methods, which weighs in your consideration of which one to use in your application.
List<T> MSDN link
You would because defining an IList or an ICollection would open up for other implementations of your interfaces.
You might want to have an IOrderRepository that defines a collection of orders in either a IList or ICollection. You could then have different kinds of implementations to provide a list of orders as long as they conform to "rules" defined by your IList or ICollection.
IList<> is almost always preferable as per the other poster's advice, however note there is a bug in .NET 3.5 sp 1 when running an IList<> through more than one cycle of serialization / deserialization with the WCF DataContractSerializer.
There is now a SP to fix this bug : KB 971030
The interface ensures that you at least get the methods you are expecting; being aware of the definition of the interface ie. all abstract methods that are there to be implemented by any class inheriting the interface. so if some one makes a huge class of his own with several methods besides the ones he inherited from the interface for some addition functionality, and those are of no use to you, its better to use a reference to a subclass (in this case the interface) and assign the concrete class object to it.
additional advantage is that your code is safe from any changes to concrete class as you are subscribing to only few of the methods of concrete class and those are the ones that are going to be there as long as the concrete class inherits from the interface you are using. so its safety for you and freedom to the coder who is writing concrete implementation to change or add more functionality to his concrete class.
You can look at this argument from several angles including the one of a purely OO approach which says to program against an Interface not an implementation. With this thought, using IList follows the same principal as passing around and using Interfaces that you define from scratch. I also believe in the scalability and flexibility factors provided by an Interface in general. If a class implmenting IList<T> needs to be extended or changed, the consuming code does not have to change; it knows what the IList Interface contract adheres to. However using a concrete implementation and List<T> on a class that changes, could cause the calling code to need to be changed as well. This is because a class adhering to IList<T> guarantees a certain behavior that is not guaranteed by a concrete type using List<T>.
Also having the power to do something like modify the default implementation of List<T> on a class Implementing IList<T> for say the .Add, .Remove or any other IList method gives the developer a lot of flexibility and power, otherwise predefined by List<T>
Typically, a good approach is to use IList in your public facing API (when appropriate, and list semantics are needed), and then List internally to implement the API. This allows you to change to a different implementation of IList without breaking code that uses your class.
The class name List may be changed in next .net framework but the interface is never going to change as interface is contract.
Note that, if your API is only going to be used in foreach loops, etc, then you might want to consider just exposing IEnumerable instead.
I have a class called Primes and this class implements GetEnumerator() without implementing IEnumerable interface.
public class Primes
{
private long min;
private long max;
public Primes()
: this(2, 100)
{
}
public IEnumerator GetEnumerator()
{...}
I don't get it. Am I missing something?
Firstly, as others have said you can introduce your own methods without implementing interfaces anyway - you can write your own Dispose method without implementing IDisposable etc. For well-known interfaces I'd suggest this is almost a bad idea (as readers will have certain expectations) but it's entirely valid.
More importantly though, the foreach statement in C# can work without IEnumerable being involved. The compiler effectively does compile-time duck typing on the names GetEnumerator(), Current and MoveNext(). This was primarily to allow strongly-typed (and non-boxing) iteration in C# 1, before generics. See section 8.8.4 of the C# 3 spec for more details.
However, it's generally a bad idea to do this now if you do want to be able to easily iterate over the contents of an instance as a collection - and indeed I'd suggest implementing IEnumerable<T> instead of just IEnumerable.
yes you can. even you can use it in foreach. The only problem that objects of this class can't be cast to IEnumerable although they implement needed method.
There's no reason that you have to implement IEnumerable in order to create a function called GetEnumerator that returns an IEnumerator, that just means that you won't be able to supply an instance of that type to something that expects an IEnumerable.
an interface ensures a contract, that does not mean that you can't have a method with the same signature as one in the interface on a class that does not impliment the interface.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Can anyone explain to me why I would want to use IList over List in C#?
Related question: Why is it considered bad to expose List<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.
The less popular answer is programmers like to pretend their software is going to be re-used the world over, when infact the majority of projects will be maintained by a small amount of people and however nice interface-related soundbites are, you're deluding yourself.
Architecture Astronauts. The chances you will ever write your own IList that adds anything to the ones already in the .NET framework are so remote that it's theoretical jelly tots reserved for "best practices".
Obviously if you are being asked which you use in an interview, you say IList, smile, and both look pleased at yourselves for being so clever. Or for a public facing API, IList. Hopefully you get my point.
Interface is a promise (or a contract).
As it is always with the promises - smaller the better.
Some people say "always use IList<T> instead of List<T>".
They want you to change your method signatures from void Foo(List<T> input) to void Foo(IList<T> input).
These people are wrong.
It's more nuanced than that. If you are returning an IList<T> as part of the public interface to your library, you leave yourself interesting options to perhaps make a custom list in the future. You may not ever need that option, but it's an argument. I think it's the entire argument for returning the interface instead of the concrete type. It's worth mentioning, but in this case it has a serious flaw.
As a minor counterargument, you may find every single caller needs a List<T> anyway, and the calling code is littered with .ToList()
But far more importantly, if you are accepting an IList as a parameter you'd better be careful, because IList<T> and List<T> do not behave the same way. Despite the similarity in name, and despite sharing an interface they do not expose the same contract.
Suppose you have this method:
public Foo(List<int> a)
{
a.Add(someNumber);
}
A helpful colleague "refactors" the method to accept IList<int>.
Your code is now broken, because int[] implements IList<int>, but is of fixed size. The contract for ICollection<T> (the base of IList<T>) requires the code that uses it to check the IsReadOnly flag before attempting to add or remove items from the collection. The contract for List<T> does not.
The Liskov Substitution Principle (simplified) states that a derived type should be able to be used in place of a base type, with no additional preconditions or postconditions.
This feels like it breaks the Liskov substitution principle.
int[] array = new[] {1, 2, 3};
IList<int> ilist = array;
ilist.Add(4); // throws System.NotSupportedException
ilist.Insert(0, 0); // throws System.NotSupportedException
ilist.Remove(3); // throws System.NotSupportedException
ilist.RemoveAt(0); // throws System.NotSupportedException
But it doesn't. The answer to this is that the example used IList<T>/ICollection<T> wrong. If you use an ICollection<T> you need to check the IsReadOnly flag.
if (!ilist.IsReadOnly)
{
ilist.Add(4);
ilist.Insert(0, 0);
ilist.Remove(3);
ilist.RemoveAt(0);
}
else
{
// what were you planning to do if you were given a read only list anyway?
}
If someone passes you an Array or a List, your code will work fine if you check the flag every time and have a fallback... But really; who does that? Don't you know in advance if your method needs a list that can take additional members; don't you specify that in the method signature? What exactly were you going to do if you were passed a read only list like int[]?
You can substitute a List<T> into code that uses IList<T>/ICollection<T> correctly. You cannot guarantee that you can substitute an IList<T>/ICollection<T> into code that uses List<T>.
There's an appeal to the Single Responsibility Principle / Interface Segregation Principle in a lot of the arguments to use abstractions instead of concrete types - depend on the narrowest possible interface. In most cases, if you are using a List<T> and you think you could use a narrower interface instead - why not IEnumerable<T>? This is often a better fit if you don't need to add items. If you need to add to the collection, use the concrete type, List<T>.
For me IList<T> (and ICollection<T>) is the worst part of the .NET framework. IsReadOnly violates the principle of least surprise. A class, such as Array, which never allows adding, inserting or removing items should not implement an interface with Add, Insert and Remove methods. (see also https://softwareengineering.stackexchange.com/questions/306105/implementing-an-interface-when-you-dont-need-one-of-the-properties)
Is IList<T> a good fit for your organisation? If a colleague asks you to change a method signature to use IList<T> instead of List<T>, ask them how they'd add an element to an IList<T>. If they don't know about IsReadOnly (and most people don't), then don't use IList<T>. Ever.
Note that the IsReadOnly flag comes from ICollection<T>, and indicates whether items can be added or removed from the collection; but just to really confuse things, it does not indicate whether they can be replaced, which in the case of Arrays (which return IsReadOnlys == true) can be.
For more on IsReadOnly, see msdn definition of ICollection<T>.IsReadOnly
List<T> is a specific implementation of IList<T>, which is a container that can be addressed the same way as a linear array T[] using an integer index. When you specify IList<T> as the type of the method's argument, you only specify that you need certain capabilities of the container.
For example, the interface specification does not enforce a specific data structure to be used. The implementation of List<T> happens to the same performance for accessing, deleting and adding elements as a linear array. However, you could imagine an implementation that is backed by a linked list instead, for which adding elements to the end is cheaper (constant-time) but random-access much more expensive. (Note that the .NET LinkedList<T> does not implement IList<T>.)
This example also tells you that there may be situations when you need to specify the implementation, not the interface, in the argument list: In this example, whenever you require a particular access performance characteristic. This is usually guaranteed for a specific implementation of a container (List<T> documentation: "It implements the IList<T> generic interface using an array whose size is dynamically increased as required.").
Additionally, you might want to consider exposing the least functionality you need. For example. if you don't need to change the content of the list, you should probably consider using IEnumerable<T>, which IList<T> extends.
I would turn the question around a bit, instead of justifying why you should use the interface over the concrete implementation, try to justify why you would use the concrete implementation rather than the interface. If you can't justify it, use the interface.
IList<T> is an interface so you can inherit another class and still implement IList<T> while inheriting List<T> prevents you to do so.
For example if there is a class A and your class B inherits it then you can't use List<T>
class A : B, IList<T> { ... }
public void Foo(IList<Bar> list)
{
// Do Something with the list here.
}
In this case you could pass in any class which implements the IList<Bar> interface. If you used List<Bar> instead, only a List<Bar> instance could be passed in.
The IList<Bar> way is more loosely coupled than the List<Bar> way.
A principle of TDD and OOP generally is programming to an interface not an implementation.
In this specific case since you're essentially talking about a language construct, not a custom one it generally won't matter, but say for example that you found List didn't support something you needed. If you had used IList in the rest of the app you could extend List with your own custom class and still be able to pass that around without refactoring.
The cost to do this is minimal, why not save yourself the headache later? It's what the interface principle is all about.
The most important case for using interfaces over implementations is in the parameters to your API. If your API takes a List parameter, then anyone who uses it has to use List. If the parameter type is IList, then the caller has much more freedom, and can use classes you never heard about, which may not even have existed when your code was written.
Supprising that none of these List vs IList questions (or answers) mentions the signature difference. (Which is why I searched for this question on SO!)
So here's the methods contained by List that are not found in IList, at least as of .NET 4.5 (circa 2015)
AddRange
AsReadOnly
BinarySearch
Capacity
ConvertAll
Exists
Find
FindAll
FindIndex
FindLast
FindLastIndex
ForEach
GetRange
InsertRange
LastIndexOf
RemoveAll
RemoveRange
Reverse
Sort
ToArray
TrimExcess
TrueForAll
What if .NET 5.0 replaces System.Collections.Generic.List<T> to System.Collection.Generics.LinearList<T>. .NET always owns the name List<T> but they guarantee that IList<T> is a contract. So IMHO we (atleast I) are not supposed to use someone's name (though it is .NET in this case) and get into trouble later.
In case of using IList<T>, the caller is always guareented things to work, and the implementer is free to change the underlying collection to any alternative concrete implementation of IList
All concepts are basically stated in most of the answers above regarding why use interface over concrete implementations.
IList<T> defines those methods (not including extension methods)
IList<T> MSDN link
Add
Clear
Contains
CopyTo
GetEnumerator
IndexOf
Insert
Remove
RemoveAt
List<T> implements those nine methods (not including extension methods), on top of that it has about 41 public methods, which weighs in your consideration of which one to use in your application.
List<T> MSDN link
You would because defining an IList or an ICollection would open up for other implementations of your interfaces.
You might want to have an IOrderRepository that defines a collection of orders in either a IList or ICollection. You could then have different kinds of implementations to provide a list of orders as long as they conform to "rules" defined by your IList or ICollection.
IList<> is almost always preferable as per the other poster's advice, however note there is a bug in .NET 3.5 sp 1 when running an IList<> through more than one cycle of serialization / deserialization with the WCF DataContractSerializer.
There is now a SP to fix this bug : KB 971030
The interface ensures that you at least get the methods you are expecting; being aware of the definition of the interface ie. all abstract methods that are there to be implemented by any class inheriting the interface. so if some one makes a huge class of his own with several methods besides the ones he inherited from the interface for some addition functionality, and those are of no use to you, its better to use a reference to a subclass (in this case the interface) and assign the concrete class object to it.
additional advantage is that your code is safe from any changes to concrete class as you are subscribing to only few of the methods of concrete class and those are the ones that are going to be there as long as the concrete class inherits from the interface you are using. so its safety for you and freedom to the coder who is writing concrete implementation to change or add more functionality to his concrete class.
You can look at this argument from several angles including the one of a purely OO approach which says to program against an Interface not an implementation. With this thought, using IList follows the same principal as passing around and using Interfaces that you define from scratch. I also believe in the scalability and flexibility factors provided by an Interface in general. If a class implmenting IList<T> needs to be extended or changed, the consuming code does not have to change; it knows what the IList Interface contract adheres to. However using a concrete implementation and List<T> on a class that changes, could cause the calling code to need to be changed as well. This is because a class adhering to IList<T> guarantees a certain behavior that is not guaranteed by a concrete type using List<T>.
Also having the power to do something like modify the default implementation of List<T> on a class Implementing IList<T> for say the .Add, .Remove or any other IList method gives the developer a lot of flexibility and power, otherwise predefined by List<T>
Typically, a good approach is to use IList in your public facing API (when appropriate, and list semantics are needed), and then List internally to implement the API. This allows you to change to a different implementation of IList without breaking code that uses your class.
The class name List may be changed in next .net framework but the interface is never going to change as interface is contract.
Note that, if your API is only going to be used in foreach loops, etc, then you might want to consider just exposing IEnumerable instead.