用不同的名称覆盖 final (IL) / sealed (C#) 方法是否合法?

Is overriding a final (IL) / sealed (C#) method with a different name legal?

我有一个层次结构 classes:

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() overrides M1()),说是重写base上的方法class(C1::M1()),a la显式接口实现,和中间的"final"(C2)class无所谓了。

.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 会很乐意 assemble 它,它在 ILSpy 中显示为

public class C3 : C2
{
    object C1.M1_2()

然后在同一个class中,你可以定义一个new M1调用this.M1_2()。 所以你有 1) 重写 M1(使用不同的名称,但仍然......)和 2)在 C3 中有一个 M1 方法(它是一个 "bridge",但它是你见)。

但看起来……不对。还是合法的?

如果你打电话

C1 obj = new C3();
obj.M1();

然后 M1_2 被正确调用(我在调试器中验证了它)。似乎 CLR 仅在链是直接的 (C1::M1 > C2::M1 > C3::M1) 时才强制执行 final 约束,如果您在层次结构 (C1::M1 > C3::M1_2) 上执行 "jump" 则不会。不过,您必须选择一个不同的名称。如果您使用相同的名称 (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

Additional information: Declaration referenced in a method implementation cannot be a final method Which is totally expected.

我想知道:那些是 CLR 规则,还是我只是在实现中发现了一个极端情况? (规则中的极端情况会很好,在实施中..你不能指望它;))

看起来像是规范中的边缘案例。

在 ECMA-335 中,分区 II 第 22.27 节 MethodImpl:

  1. MethodDeclaration shall index a method in the ancestor chain of Class (reached via its Extends chain) or in the interface tree of Class (reached via its InterfaceImpl entries) [ERROR]

  2. The method indexed by MethodDeclaration shall not be final (its Flags.Final shall be 0) [ERROR]

因此,您尝试重写的特定方法不得密封,必须在祖先 class 上定义,但不要求指定的特定方法是您的插槽中最具体的重写祖先链.

话虽如此,未来的版本可能会对执行此类操作施加安全限制,这可能“完全出乎意料”。