views:

1358

answers:

4

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.

+6  A: 

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.

Jon Skeet
+1  A: 

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.

jezell
This a important point. IList<string> cannot be casted to IList<object>.
Morgan Cheng
+34  A: 

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! :-)

Mark Brackett
That's interesting... I was really annoyed that `IList<T>` didn't inherit `IList`, but as soon as you take variance into account it starts to make sense...
Thomas Levesque
+2  A: 

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();
    }
Mendelt
When implementing IEnumerable<T>, you're required to also implement the private IEnumerable.GetEnumerator() method. Fortunately, the code above does well, so you're not duplicating effort.
spoulson
@spoulson: Not private. It's part of an interface, so it must be implemented publicly. Mendelt's example doesn't implement it privately, it implements it explicitly, so that it is only available when the object is cast to IEnumerable.
Joel B Fant
@spoulson: The second two methods were generated when I clicked implement interface in visual studio, didn't really look at it. You can just add a using for System.Collections and make the third function explicitly public.
Mendelt