考虑以下代码:
interface I {
string M1() => "I.M1";
string M2() => "I.M2";
}
abstract class A : I {}
class C : A {
public string M1() => "C.M1";
public virtual string M2() => "C.M2";
}
class Program {
static void Main() {
I obj = new C();
System.Console.WriteLine(obj.M1());
System.Console.WriteLine(obj.M2());
}
}
它在 .NET Core 3.1.402 中产生以下意外输出:
I.M1
C.M2
类A
没有 的成员的隐式或显式实现I
,因此我希望默认实现用于C
,因为C
继承了 的接口映射A
并且没有显式地重新实现I
。根据 ECMA-334 (18.6.6) 和 C# 6.0 语言规范:
一个类继承其基类提供的所有接口实现。
如果不显式地重新实现接口,派生类就不能以任何方式更改它从其基类继承的接口映射。
特别是,我希望得到以下输出:
I.M1
I.M2
这确实A
是未声明为抽象时发生的情况。
上述代码的行为是在 C# 8.0 中设计的,还是某个错误的结果?如果有意,为什么只有在声明为 virtual(在但不是的情况下)并且仅在声明为抽象时才C
隐式实现相应的成员?I
M2
M1
A
编辑:
虽然我仍然不清楚这是一个错误还是一个功能(我倾向于认为这是一个错误,并且第一条评论中链接的讨论到目前为止还没有定论),但我想出了一个更危险的场景:
class Library {
private interface I {
string Method() => "Library.I.Method";
}
public abstract class A: I {
public string OtherMethod() => ((I)this).Method();
}
}
class Program {
private class C: Library.A {
public virtual string Method() => "Program.C.Method";
}
static void Main() {
C obj = new C();
System.Console.WriteLine(obj.OtherMethod());
}
}
请注意,接口Library.I
和类对于各自的类Program.C
是私有的。特别是,该方法Program.C.Method
应该不能从类外部访问Program
。类的作者Program
可能认为可以完全控制何时Program.C.Method
调用方法,甚至可能不知道接口Library.I
(因为它是私有的)。但是,它是从 调用的Library.A.OtherMethod
,因为输出是:
Program.C.Method
这看起来像是一种脆弱的基类问题。被宣布为公开的事实Program.C.Method
应该是无关紧要的。请参阅 Eric Lippert 的这篇博客文章,其中描述了一个不同但有些相似的场景。