Fit*_*Dev 5 .net c# c#-8.0 .net-core-3.0 default-interface-member
考虑代码:
class ChildClass : BaseClass {
public void Method1() {} //some other method
}
abstract class BaseClass : IChildInterface {
public
virtual //<- If we add virtual so that this method can be overridden by ChildClass, we get StackOverflowException and DoWork() implementation in IChildInterface is never called.
void DoWork() {
//base class specific implmentation
((IChildInterface)this).DoWork(); //call into default implementation provided by IChildInterface
}
}
interface IChildInterface : IBaseInterface {
void IBaseInterface.DoWork() {
//implmentation
}
}
interface IBaseInterface {
void DoWork();
}
Run Code Online (Sandbox Code Playgroud)
问题是,如果我们庆祝DoWork()的BaseClass是virtual,这样它可以通过子类覆盖,防止它从调入IChildInterface的缺省实现DoWork(),引起StackOverflowException。
如果我们virtual从DoWork()中删除修饰符BaseClass,则一切正常,并且调用IChildInterface的默认实现。DoWork()
这种行为是错误还是有意为之?
有没有办法让某些子类可以提供他们自己的实现DoWork()(从而覆盖BaseClass的实现),但仍然能够使用 IChildInterface的默认实现DoWork()?
您正在递归BaseClass.DoWork调用,如果幸运的话,将导致 StackOverflowException。如果调用是方法中的最后一个调用,则由于尾调用优化,您将获得无限递归。你最终会发现核心卡在 100%,直到你终止该应用程序。
这段代码:
public virtual void DoWork() {
((IChildInterface)this).DoWork(); by IChildInterface
}
Run Code Online (Sandbox Code Playgroud)
等同于:
//That's the actual implementation of the interface method
public virtual void DoWork() {
DoWork();
}
Run Code Online (Sandbox Code Playgroud)
关键字virtual并不重要。没有它你仍然会得到无限递归。无论它是否存在,这一行都会在一段时间后抛出 StackOverflowException :
new ChildClass().DoWork();
Run Code Online (Sandbox Code Playgroud)
当您实现时BaseClass.DoWork,它就成为每个人都可以使用的单一实现,除非被子类覆盖。
即使在 C# 8 中,接口也不是抽象类。默认方法实现不是实际方法。顾名思义,这是一个默认实现。当没有更好的实现可用时使用它。当该方法已在类中实现时,您无法调用默认实现。
事实上,几乎在所有情况下,您都不会期望调用默认方法。DIM 通过接口显式调用,与使用显式接口实现的方式相同。该方法的调用者期望运行最派生的实现,而不是基础或中级实现。
此外,即使在以前的 C# 版本中,您也不会期望通过转换为接口来更改实际调用的方法。你只希望在课堂上能做到这一点。要调用基类实现,您可以使用关键字base。BaseClasswhile的基类Object没有方法DoWork。
如果您使用:
void DoWork() {
base.DoWork();
}
Run Code Online (Sandbox Code Playgroud)
你会得到一个CS0117: 'object' does not contain a definition for 'DoWork'
更新
C# 设计团队已经考虑过这一点。如果没有运行时支持,这无法有效实现,并于 2019 年 5 月被削减。运行时优化使得 DIM 调用与其他调用一样便宜,无需装箱等。
建议的语法是调用base(IMyInterface):
interface I1
{
void M(int) { }
}
interface I2
{
void M(short) { }
}
interface I3
{
override void I1.M(int) { }
}
interface I4 : I3
{
void M2()
{
base(I3).M(0) // What does this do?
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |