我有一个类的层次结构:
class C1 { virtual object M1(); }
class C2: C1 { override sealed object M1(); }
class C3: C2 {
// I want to override M1()
// CSC gives me an error, obviously
override object M1();
}
但似乎有办法。在IL中,您可以使用其他名称覆盖方法。因此,我们更改名称(M1_2()
覆盖M1()
),说它覆盖了基类(C1::M1()
)上的方法, a la 显式接口实现,而且中间(C2
)类的“final”不再重要。
.class public auto ansi beforefieldinit N.C3
extends N.C2
{
.method private hidebysig virtual final
instance object M1_2() cil managed
{
.override N.C1::M1
ILasm很乐意组装它,它在ILSpy中显示为
public class C3 : C2
{
object C1.M1_2()
然后在同一个班级中,您可以定义调用new M1
的{{1}}。
所以你有1)覆盖this.M1_2()
(使用不同的名称,但仍然......)和2)在C3中有一个M1
方法(它是一个“桥”,但它是你所看到的)
但看起来......错了。或者这是合法的吗?
如果你打电话
M1
然后正确调用C1 obj = new C3();
obj.M1();
(我在调试器中验证了它)。似乎CLR仅在链是直接(M1_2
)时强制执行final
约束,而不是在层次结构(C1::M1 > C2::M1 > C3::M1
)上“跳转”时强制执行C1::M1 > C3::M1_2
约束。但是,您必须选择其他名称。如果您使用相同的名称(M1):
.class public auto ansi beforefieldinit N.C3
extends N.C2
{
.method private hidebysig virtual final
instance object M1() cil managed
{
.override N.C1::M1
无效,抛出System.TypeLoadException
附加信息:方法实现中引用的声明不能是最终方法 这完全是预期的。
我想知道:那些CLR规则,还是我刚刚在实现中发现了一个极端情况? (规则中的一个极端情况会很好,在实现中......你不能指望它;))
答案 0 :(得分:5)
看起来像规范中的边缘情况。
在ECMA-335中,分区II部分22.27 MethodImpl:
MethodDeclaration将索引Class的祖先链中的方法(通过其Extends链到达)或Class的接口树(通过其InterfaceImpl条目到达)[ERROR]
- 醇>
MethodDeclaration索引的方法不是final(Flags.Final应为0)[ERROR]
因此,您尝试覆盖的特定方法不得密封,并且必须在祖先类上定义,但不要求指定的特定方法是祖先链中该槽的最特定覆盖。
话虽如此,这可能是出乎意料的"未来版本可能会施加安全限制来执行此类操作。