C#:传递继承
C#中继承是传递关系吗?
我问这个问题是因为我无法理解为什么 IList
将 ICollection
和 IEnumerable
实现为 ICollection
已经实现了 IEnumerable
感谢您为我澄清这一点。
Is Inheritance a transitive relation in C#?
I am asking because I cannot understand why IList<T>
implements ICollection<T>
and IEnumerable<T>
as ICollection<T>
already implements IEnumerable<T>
Thanks for clarifying this for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它在所有方面都是传递性的。您用来查看继承层次结构的工具可能有某种特定的显示方式。尽管您可以显式实现接口并从而将其隐藏在智能感知中,但无法取消实现接口。
作为 IList 的作者,您可以自由选择仅从 ICollection 派生,或者从 ICollection 和 IEnumerable 派生。在这种情况下,IEnumerable 是多余的,并且会被 resharper 标记。
It is transitive in all regards. Probably the tool that you use to look at the inheritance hierarchy has a certain way of displaying it. There is no way to unimplement an interface although you can implement it explicitly and thereby hide it from intellisense.
As the author of IList you can freely choose to derive from ICollection only or from ICollection and IEnumerable. IEnumerable would be redundant in this case and flagged by resharper.
AFAIK,无论您将
IList
声明为:还是简单地声明为:
任何想要实现
IList
的类都必须实现 < em>所有这些接口,即继承的接口。显然,如果您实现此接口而不实现
IEnumerable
/IEnumerable
接口的GetEnumerator
方法,则会出现编译器错误;这个通过演示的“证明”应该足以告诉您“接口继承”确实是可传递的。旁注 1. 旁注(有点偏离主题),请考虑您还可以执行以下操作:
Derived
实际上并未实现IFoo;它的基类
Base
提供了方法Foo
,但没有显式实现IFoo
本身。这看起来编译得很好,因为接口所需的所有方法都在那里。 (我现在就将其保留下来,并暂时将确切的技术讨论放在一边。)
我之所以提到这种看似无关的现象,是因为我喜欢以这种方式思考接口继承:您需要实现所需的所有方法通过类声明中指定的接口。因此,当我看到
“
ICollection
继承IEnumerable
”而不是说“”时,我可以对自己说, “ICollection
还要求所有实现类都实现IEnumerable
。”旁注 2。用另一个有些相关的轶事来结束这个答案(我保证这将是最后一个):
不久前我观看了视频 .NET Rx 和 IObservable 内部/
IObserver
位于第 9 频道的 BCL 中。正如您现在可能看到的,这两个新接口来自 Rx 是通过 .NET 4 引入到 BCL 中的。一个奇怪的事情是,当您通过observable 订阅一个观察者到一个可观察对象时.Subscribe(observer)
,你得到的只是一些匿名的IDisposable
。为什么?,他们可以通过定义如下的类型名称“别名”为
IDisposable
指定一个更具描述性的名称(例如ISubscription
):正如演讲者在该视频中所解释的那样 ,他们最终决定不这样做。他们认为,一旦从
Subscribe
方法返回ISubscription
,返回值需要进行Dipose
处理就不再明显了。因此,这是人们应该牢记的“接口继承”的另一个稍微有问题的方面。
AFAIK, it doesn't truly matter whether you declared
IList<T>
as:or simply as:
Any class that wants to implement
IList<T>
will have to implement all of these interfaces, i.e. also the inherited ones.Obviously, if you implemented this interface without implementing the
GetEnumerator
methods of theIEnumerable
/IEnumerable<T>
interfaces, you'd get a compiler error; this "proof" by demonstration should be enough to tell you that "interface inheritance" is transitive, indeed.Sidenote 1. On a side note (and slightly off-topic), consider that you can also do the following:
Derived
doesn't actually implementIFoo
; its base classBase
provides methodFoo
, but doesn't explicitly implementIFoo
itself.This compiles well, seemingly because all the methods that are required by the interfaces are there. (I'll leave it at that and leave the exact technical talk aside for now.)
The reason why I'm mentioning this seemingly unrelated phenomenon is that I like to think of interface inheritance in this way: You need to implement all methods required by the interfaces specified in the class declaration. So when I see
instead of saying, "
ICollection<T>
inheritsIEnumerable<T>
", I could say to myself, "ICollection<T>
requires of all implementing classes that they implementIEnumerable<T>
, also."Sidenote 2. To conclude this answer with yet another somewhat related anecdote (I promise it'll be the last one):
Some time ago I watched the video Inside .NET Rx and
IObservable
/IObserver
in the BCL on Channel 9. As you might now, those two new interfaces, coming from Rx, were introduced into the BCL with .NET 4. One peculiar thing is that when you subscribe an observer to an observable viaobservable.Subscribe(observer)
, all you get back is some anonymousIDisposable
. Why?As the talkers explain in that video, they could have given the
IDisposable
a more descriptive name (such asISubscription
), via a type name "alias" defined as follows:However, they finally decided against this. They figured that once an
ISubscription
is returned from theSubscribe
method, it would no longer be obvious that the returned value needs to beDipose
d.So that's another slightly problematic side of "interface inheritance" that one should keep in mind.