简体   繁体   English

为什么 IEnumerable<T> 从 IEnumerable 继承?

[英]Why does IEnumerable<T> inherit from IEnumerable?

This might be a old question: Why does IEnumerable<T> inherit from IEnumerable ?这可能是一个老问题:为什么IEnumerable<T>继承自IEnumerable

This is how .NET do, but it brings a little trouble.这就是 .NET 的做法,但它带来了一些麻烦。 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 .每次我写一个类实现IEumerable<T> ,我必须写两个GetEnumerator()函数,一个用于IEnumerable<T> ,另一个用于IEnumerable

And, IList<T> doesn't inherit from IList.而且, IList<T>不继承自 IList。

I don't know why IEnumerable<T> is designed in other way.我不知道为什么IEnumerable<T>是以其他方式设计的。

Straight from the horse's mouth (Hejlsberg): 直接从马口(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.理想情况下,所有泛型集合接口(例如ICollection<T>IList<T> )都将从其非泛型对应物继承,以便泛型接口实例可以与泛型和非泛型代码一起使用。 For example, it would be convenient if an IList<T> could be passed to code that expects an IList .例如,如果可以将IList<T>传递给需要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).事实证明,唯一可能的通用接口是IEnumerable<T> ,因为只有IEnumerable<T>是逆变的:在IEnumerable<T> ,类型参数 T 仅用于“输出”位置(返回值)而不是“输入”位置(参数)。 ICollection<T> and IList<T> use T in both input and output positions, and those interfaces are therefore invariant. ICollection<T>IList<T>在输入和输出位置都使用 T,因此这些接口是不变的。 (As an aside, they would have been contra-variant if T was used only in input positions, but that doesn't really matter here.) (顺便说一句,如果 T 仅用于输入位置,它们将是逆变的,但这在这里并不重要。)

<...snip...> <...剪...>

So, to answer your question, IEnumerable<T> inherits from IEnumerable because it can!因此,为了回答您的问题, IEnumerable<T>继承自IEnumerable因为它可以! :-) :-)

The answer for IEnumerable is: "because it can without affecting type safety". IEnumerable的答案是:“因为它可以不影响类型安全”。

IEnumerable is a "readonly" interface - so it doesn't matter that the generic form is more specific than the nongeneric form. IEnumerable是一个“只读”接口——所以通用形式比非通用形式更具体并不重要。 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. IEnumerator.Current返回object ,而IEnumerator<T>.Current返回T - 没关系,因为您总是可以合法地转换为object ,尽管它可能意味着装箱。

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).将此与IList<T>IList - 您可以在IList上调用Add(object) ,而这对于任何特定的IList<T> (实际上不是IList<object> )很可能无效。

Brad Abram's blogged with Anders' answer about this very question. Brad Abram 在博客上写了 Anders对这个问题的回答。

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.如果您调用一个需要普通 IEnumerable 的 .Net 1.1 函数,您可以传入您的通用 IEnumerable。

Luckilly the generic IEnumerator inherits from the old-style IEnumerator幸运的是,通用 IEnumerator 继承自旧式 IEnumerator

I usually implement a private method that returns an enumerator and then pass it for both the old and new style GetEnumerator method.我通常实现一个私有方法,它返回一个枚举器,然后将它传递给新旧样式的 GetEnumerator 方法。

    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.此外,.NET 泛型不允许您执行诸如将 IList<long> 转换为 IList<int> 之类的操作,因此当您需要固定基类或接口时,接口的非泛型版本可能非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么GetEnumerator在COM中对于从IEnumerable继承的.Net类不可见 <T> ? - Why is GetEnumerator not visible in COM for .Net classes that inherit from IEnumerable<T>? 从IEnumerable <IEnumerable <T >>获取IEnumerable <T> - Get a IEnumerable<T> from a IEnumerable<IEnumerable<T>> 为什么ICollection <T>实现IEnumerable <T>和IEnumerable - Why does ICollection<T> implement both IEnumerable<T> and IEnumerable 采集 <T> :为什么同时实现IEnumerable和IEnumerable <T> ? - Collection<T>: why does it implement both IEnumerable and IEnumerable<T>? 为什么编译器选择IEnumerable超过IEnumerable <T>的重载? - Why does the compiler choose overload with IEnumerable over IEnumerable<T>? 为什么XmlSerializer要求从IEnumerable继承的类型具有Add(System.Object)的实现? - Why does XmlSerializer require types which inherit from IEnumerable to have an implementation of Add(System.Object)? 为什么IGrouping不继承IEnumerable <KeyValuePair> 喜欢IDictionary? - Why doesn't IGrouping inherit IEnumerable<KeyValuePair> like IDictionary? 如何从IEnumerable转换为IEnumerable <T> ? - How does one convert from an IEnumerable to IEnumerable<T>? 使不从IEnumerable &lt;&gt;继承的对象可通过LINQ查询 - Making Objects that Don't Inherit from IEnumerable<> Queryable via LINQ 无法从IEnumerable转换 <T> 到IEnumerable <T> - cannot convert from IEnumerable<T> to IEnumerable<T>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM