才是硬道理用不同的名称法律的最终(IL)/密封(C#)的方法? [英] Is overriding a final (IL) / sealed (C#) method with a different name legal?

查看:224
本文介绍了才是硬道理用不同的名称法律的最终(IL)/密封(C#)的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的类层次:

 类C1 {虚拟对象M1(); } 

类C2:C1 {覆盖密封对象M1(); }

级C3:C2 {
//我要重写M1()
// CSC给我一个错误,显然
改写对象M1();
}



但似乎有一种方法。在IL,您可以覆盖具有不同名称的方法。所以,我们改变名称( M1_2()覆盖 M1()),说它将覆盖方法的基础上,类( C1 :: M1())的一拉的显式接口实现,并在中间( C2 )类不再重要。

 的.class众汽车ANSI beforefieldinit N.C3 
扩展N.C2
{
。方法私人hidebysig虚拟决赛
实例对象M1_2()CIL管理
{
.override N.C1 :: M1

ILASM会很乐意进行组装,它显示了在ILSpy为

 公共类C3:C2 
{
对象C1.M1_2()

然后在同一个班级,你可以定义一个新M1 这就要求 this.M1_2 ()
所以,你有1)重写 M1 (使用不同的名称,但仍...)和2)有一个 M1 在C3的方法(这是一个桥梁,但它是你所看到的)。



但它看起来...错了。又或者是合法的吗?



如果你调用

  C1 OBJ =新C3(); 
obj.M1();



然后 M1_2 正确调用(我核实它在调试器)。看来,CLR强制只有链是直接的最后约束( C1 :: M1> C2 :: M1> C3 :: M1 ),而不是如果你做跳过层级( C1 :: M1> C3 :: M1_2 )。你必须选择一个不同的名字,虽然。如果您使用相同的名称(M1):

 的.class众汽车ANSI beforefieldinit N.C3 
扩展N. C2
{
。方法私人hidebysig虚拟决赛
实例对象M1()CIL管理
{
.override N.C1 :: M1

将无法正常工作,丢个 System.TypeLoadException




其他信息:在方法实现中引用的声明不能是最终方法
这完全是预料




我想知道:那些CLR的规则,或者我刚刚发现在执行一个角落里呢? (在规则的一角情况下就可以了,在执行..你不能指望它;))


解决方案

相貌。像在规范中的边缘情况



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





  • MethodDeclaration应当指数类的祖先链的方法(通过其延伸链达到),或在类的接口树(通过达到InterfaceImpl条目)[错误]


  • 由MethodDeclaration索引将不会被最终确认的方法(它Flags.Final应为0)[错误]





  • 所以你想覆盖特定的方法不能密封,必须在一个父类中定义,但不要求指定具体方法是在你的祖先链的插槽中的最具体的覆盖。



    说了这么多,这可能是足够的意外未来版本可能会强制执行安全限制做这种事情。


    I have a hierarchy of 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();
    }
    

    But it seems there is a way. In IL, you can override a method with a different name. So, we change the name (M1_2() overrides M1()), say it overrides the method on the base class (C1::M1()), a la explicit interface implementation, and the "final" on the intermediate (C2) class does not matter anymore.

    .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 will happily assemble it, and it shows in ILSpy as

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

    Then in the same class, you can define a new M1 which calls this.M1_2(). So you have 1) overridden M1 (with a different name, but still...) and 2) have a M1 method in C3 (it is a "bridge", but it's what you see).

    But it looks... wrong. Or is it something legal?

    If you call

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

    then M1_2 is called correctly (I verified it in the debugger). It seems that the CLR enforces the final constraint only if the chain is direct (C1::M1 > C2::M1 > C3::M1) and not if you do "jump" over the hierarchy (C1::M1 > C3::M1_2). You have to choose a different name, though. If you use the same name (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
    

    will not work, throwing a System.TypeLoadException

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

    I wonder: are those CLR rules, or I just found a corner case in the implementation? (A corner case in the rules would be fine, in the implementation.. you cannot count on it ;) )

    解决方案

    Looks like an edge case in the specification.

    In ECMA-335, Partition II section 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]

    So the specific method you try to override must not be sealed and must be defined on an ancestor class, but there is no requirement that the specific method specified is the most specific override for that slot in your ancestor chain.

    Having said that, this is probably "sufficiently unexpected" that future versions may impose security restrictions to do this sort of thing.

    这篇关于才是硬道理用不同的名称法律的最终(IL)/密封(C#)的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆