This might be a old question: Why does IEnumerable<T>
inherit from IEnumerable
?
This is how .NET do, but it brings a little trouble. Every time I write a class implements IEumerable<T>
, I have to write two GetEnumerator()
functions, one for IEnumerable<T>
and the other for IEnumerable
.
And, IList<T>
doesn't inherit from IList.
I don't know why IEnumerable<T>
is designed in other way.
Straight from the horse's mouth (Hejlsberg):
Ideally all of the generic collection interfaces (e.g. ICollection<T>
, IList<T>
) would inherit from their non-generic counterparts such that generic interface instances could be used both with generic and non-generic code. For example, it would be convenient if an IList<T>
could be passed to code that expects an IList
.
As it turns out, the only generic interface for which this is possible is IEnumerable<T>
, because only IEnumerable<T>
is contra-variant: In IEnumerable<T>
, the type parameter T is used only in "output" positions (return values) and not in "input" positions (parameters). ICollection<T>
and IList<T>
use T in both input and output positions, and those interfaces are therefore invariant. (As an aside, they would have been contra-variant if T was used only in input positions, but that doesn't really matter here.)
<...snip...>
So, to answer your question, IEnumerable<T>
inherits from IEnumerable
because it can! :-)
The answer for IEnumerable
is: "because it can without affecting type safety".
IEnumerable
is a "readonly" interface - so it doesn't matter that the generic form is more specific than the nongeneric form. You don't break anything by implementing both. IEnumerator.Current
returns object
, whereas IEnumerator<T>.Current
returns T
- that's okay, as you can always legitimately convert to object
, although it may mean boxing.
Compare this with IList<T>
and IList
- you can call Add(object)
on an IList
, whereas that may well be invalid for any particular IList<T>
(anything other than IList<object>
in fact).
Brad Abram's blogged with Anders' answer about this very question.
It's for backward compatibility. If you call a .Net 1.1 function that expects a vanilla IEnumerable you can pass in your generic IEnumerable.
Luckilly the generic IEnumerator inherits from the old-style IEnumerator
I usually implement a private method that returns an enumerator and then pass it for both the old and new style GetEnumerator method.
private IEnumerator<string> Enumerator() {
// ...
}
public IEnumerator<string> GetEnumerator() {
return Enumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return Enumerator();
}
This is so that it will work with classes that do not support generics. Additionally, .NET generics don't let you do things like cast IList<long> as IList<int>, so non generic versions of interfaces can be quite useful when you need a fixed base class or interface.