是否覆盖了具有不同名称的最终(IL)/密封(C#)方法?

时间:2015-11-26 19:17:33

标签: c# override clr cil

我有一个类的层次结构:

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规则,还是我刚刚在实现中发现了一个极端情况? (规则中的一个极端情况会很好,在实现中......你不能指望它;))

1 个答案:

答案 0 :(得分:5)

看起来像规范中的边缘情况。

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

  
      
  1. MethodDeclaration将索引Class的祖先链中的方法(通过其Extends链到达)或Class的接口树(通过其InterfaceImpl条目到达)[ERROR]

  2.   
  3. MethodDeclaration索引的方法不是final(Flags.Final应为0)[ERROR]

  4.   

因此,您尝试覆盖的特定方法不得密封,并且必须在祖先类上定义,但不要求指定的特定方法是祖先链中该槽的最特定覆盖。

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