C#中接口带默认实现成员的virtual修饰符作用及相关疑问
C#中接口带默认实现成员的virtual修饰符作用及相关疑问
我完全懂你的困惑!当初我第一次在带默认实现的接口成员上加virtual时,也摸不着头脑——毕竟从直觉上会觉得它应该让实现类的继承链能重写这个成员,但实际测试下来完全不是这么回事。
先给你拆解这个virtual修饰符的真正作用:它只作用于接口的继承链,允许子接口重写父接口的默认实现,和实现接口的类的继承体系没有直接关系。
举个例子,如果你定义一个继承自IThing的子接口,就能用override重写它的默认实现:
interface IThing { virtual string A => "A"; } interface ICustomThing : IThing { override string A => "Custom A"; }
这时候,任何实现ICustomThing但没有自己实现A的类,都会使用ICustomThing的默认实现,而不是IThing的——这才是接口成员上virtual的正确打开方式。
回到你的测试代码,为什么Thing2没法override A?原因很简单:
- 当
Thing实现IThing但没有显式声明A时,它并没有把A作为自己的类成员,只是隐式地复用了接口的默认实现。这个A本质上还是属于IThing的,不属于Thing的成员体系。 - 哪怕你让
Thing显式引用接口的默认实现,比如:
这个class Thing: IThing { public string A => IThing.A; }A也不是virtual的,除非你自己给Thing里的A加上virtual修饰符,否则Thing2依然找不到可重写的成员。
另外你提到的“代码使用IThing只看到默认实现,除非类直接实现接口”也是这个逻辑:如果类直接实现接口并自己写了A的实现,那通过IThing引用时会优先调用类的实现;但如果类是继承自另一个没显式实现A的实现类,那IThing引用的还是接口自身的默认实现——因为继承的类也没把A纳入自己的成员体系。
最后再总结几个关键点:
- 接口默认实现成员的
virtual,仅用于子接口重写父接口的默认实现,和实现类的继承无关。 - 实现类不会因为接口成员加了
virtual就自动拥有可重写的成员,必须自己显式声明该成员并添加virtual修饰符,才能让子类重写。 - 如果实现类没有自己实现接口成员,该成员始终属于接口,不属于类的成员,子类自然无法
override。
备注:内容来源于stack exchange,提问作者ZzZombo
相关产品推荐
相关产品推荐

