【问题标题】:Is overriding a final (IL) / sealed (C#) method with a different name legal?覆盖具有不同名称的最终(IL)/密封(C#)方法是否合法?
【发布时间】:2015-11-26 19:17:32
【问题描述】:

我有一个类的层次结构:

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) 类不再重要了。

.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()

然后在同一个类中,您可以定义一个调用this.M1_2()new M1。 所以你有 1) 被覆盖的 M1 (使用不同的名称,但仍然......)和 2)在 C3 中有一个 M1 方法(它是一个“桥”,但它就是你所看到的)。

但它看起来......错了。还是合法的?

如果你打电话

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

然后M1_2 被正确调用(我在调试器中验证了它)。似乎 CLR 仅在链是直接的 (C1::M1 > C2::M1 > C3::M1) 而不是在您“跳过”层次结构 (C1::M1 > C3::M1_2) 时才强制执行 final 约束。但是,您必须选择不同的名称。如果您使用相同的名称(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 规则,还是我只是在实现中发现了一个极端情况? (规则中的一个极端情况会很好,在实施中......你不能指望它;))

【问题讨论】:

  • 是什么让你尝试了这些东西并因此找到了这个? :)
  • StackOverflow 上已经询问并回答了所有简单的问题,所以......我必须找到并提出新的问题! :) 开个玩笑,我正在为此 github.com/dotnet/roslyn/issues/357 做一些研究,我不想最终找到一个可行的解决方案,但只能靠运气。
  • 你测试Peverify.exe了吗?
  • 是的...All Classes and Methods in Project3.dll Verified.

标签: c# overriding clr cil


【解决方案1】:

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

在 ECMA-335 中,第二部分第 22.27 节 MethodImpl:

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

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

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

话虽如此,未来的版本可能会施加安全限制来做这类事情,这可能是“完全出乎意料的”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    相关资源
    最近更新 更多