What is the difference between IEnumerable
and IEnumerable<T>
?
I've seen many framework classes implementing both these interfaces, therefore I would like to know what advantages one get by implementing both?
Please have a look how they've been defined:
public interface IEnumerable
{
[DispId(-4)]
IEnumerator GetEnumerator();
}
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
As we see, IEnumerable<T>
derives from IEnumerable
, that means whatever IEnumerable
has, IEnumerable<T>
inherits, then why do we implement both instead of just IEnumerable<T>
? Is implementing IEnumerable<T>
not enough?
Likewise, there are other similar pairs:
IList
andIList<T>
ICollection
andICollection<T>
I would like to know about these as well.
Basically the nongeneric interfaces came first, in .NET 1.0 and 1.1. Then when .NET 2.0 came out, the generic equivalents came out. Life would have been a lot simpler if generics had made it into .NET 1.0 :)
In terms of implementing "only"
IEnumerable<T>
instead of both - you basically have to implement both, and you have to use explicit interface implementation too, given that both define a parameterlessGetEnumerator
method. AsIEnumerator<T>
extendsIEnumerator
too, it's normally something like this:On the other hand, with the iterator blocks introduced in C# 2 (with
yield return
etc) you rarely need to implement these things entirely by hand, fortunately. You may need to write something like the above, and then useyield return
in theGetEnumerator
method.Note that
IList<T>
does not extendIList
, andICollection<T>
does not extendICollection
. That's because it's less type-safe to do so... whereas any generic iterator can be seen as a nongeneric iterator due to the (potentially boxing) conversion of any value toobject
,IList
andICollection
allow values to be added to the collection; and it doesn't make sense to add (say) a string to anIList<int>
.EDIT: The reason why we need
IEnumerable<T>
is so that we can iterate in a type-safe way, and propagate that information around. If I return anIEnumerable<string>
to you, you know that you can safely assume everything returned from it will be a string reference or null. WithIEnumerable
, we had to effectively cast (often implicitly in aforeach
statement) each element that was returned from the sequence, because theCurrent
property ofIEnumerator
is just of typeobject
. As for why we still needIEnumerable
- because old interfaces never go away, basically. There's too much existing code using it.It would have been possible for
IEnumerable<T>
not to extendIEnumerable
, but then any code wanting to make use of anIEnumerable<T>
couldn't call into a method acceptingIEnumerable
- and there were a lot of methods like that from .NET 1.1 and 1.0.