简体   繁体   中英

Why does IEnumerable<T> inherit from IEnumerable?

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM