What is the benefit to using List<T> over IEnumerable<T>?
or the other way around?
I use generic lists all the time. But I hear occasionally about IEnumerables, too, and I honestly have no clue (today) what they are for and why I should use them. So, at the risk of having something on the net forever more proclaiming my ignorance, I humbly post this开发者_如何学Go question.
Well, List<T>
implements IEnumerable<T>
... basically IEnumerable<T>
is just a sequence of items. You can read through it, and that's all.
List<T>
is a mutable collection - you can add to it, remove from it, sort it etc. It's more flexible in itself, but IEnumerable<T>
allows you to use the same code to work with any implementation (arrays, linked lists, lists, iterators returned from methods using yield
statements etc).
IEnumerable<T>
is a more general interface, so you can substitute anything that implements that interface for your operation. If you have this method:
public void DoSomething(IEnumerable<T> enumerable) {
}
It will work on arrays, collections, lists, dictionaries, and anything else that implements the interface.
If you specify that the object is a List<T>
, the method will only work on List<T>
objects or instances that inherit from it.
The advantage of using List<T>
is that lists have many more features than enumerables. When you need those features (insertion, searching, conversion, and many more), List<T>
or IList<T>
is more appropriate.
John Skeet and others have offered a good synopsis of the functionality of List over IEnumerable, so I thought I'd fill in the other half of the question which is "What are the benefits of using IEnumerable over List?".
First, IEnumerable provides a more generic contract for representing a collection of things you can iterate over and therefore allows you to adhere to the Principle of Least Privilege. In other words, IEnumerable should be preferred over its derived types where enumeration is the only behavior that needs to be exposed for the task at hand. This is beneficial because exposing information and/or behavior unnecessarily opens your API up to possible unintended usages which can pose a security issue or can cause unintended coupling between your API and its consumers.
Second, IEnumerable is an abstraction for enumeration whereas List is one implementation of that abstraction. Following the guidance of Design Patterns - Elements of Reusable Object-Oriented Software, programming to abstractions over implementations aids in making applications more resilient to change by allowing implementations to be changed later without impacting consuming code. If you do need list behavior, you should expose IList rather than List directly.
The biggest advantages of List<T>
over IEnumerable<T>
are the following
- Random access
- Count property
- ForEach method
- Mutability
The first 2 are easy to do on IEnumerable<T>
as well but you can't guarantee O(1) speed. In the case of Count you can't even guarantee a real answer as IEnumerable<T>
can easily represent infinite lists.
List provides additional methods over IEnumerable. You can't add insert or delete with IEnumerable, but you can with List.
IEnumerable should be used when you plan on looping through the data only. It gives you an advantage over IList, because you don't have to load all the data at once to pass access to the data, you just have to be able to get the next record through the enumerator. IEnumerable is also an interface, so you can "hide" the type of the actual object containing the data List, Array etc.
If you only need the functionality exposed and implemented in IEnumerable<T>
, you should go with that. An alternative is IEnumerable<T> where T : IFoo
if you want to be able to iterate over objects that implements the interface IFoo
. If you, however, require properties like Count
and such that List<T>
exposes, you should go for that. Find the lowest common denominator and go with that as it makes your methods more versatile and easier to work with.
IEnumerable has a clean read-only and 'enumerable' or 'queriable' semantics. With List it looks like you allow anybody modify it:).
One advantage to IEnumerable that hasn't yet been mentioned: Contravariance. A routine expecting an IEnumerable(Of Car) will be perfectly happy if given an IEnumerable(Of HondaCivic), which in turns means it would be happy with an IList(Of HondaCivic). By contrast, a routine which expects an IList(Of Car) will not be satisfied with an IList(of HondaCivic). If Microsoft IList were derived from a read-only IReadableByIndex interface, then code which expected an IReadableByIndex(Of Car) would be perfectly happy with IReadableByIndex(Of HondaCivic), but that's water under the bridge.
精彩评论