3

这个问题链接到当引用存储在基类变量中时,CLR 如何调用派生类正确隐藏的方法?

就我而言,我使用的是callvirt 指令,而不是call

     class BaseClass
    {
        public void Write()
        {
            Method();
        }

        protected virtual void Method()
        {
            Console.WriteLine("Base - Method");
        }
    }

    class DerivedClass : BaseClass
    {
        private new void Method()
        {
            Console.WriteLine("Derived - Method");
        }
    }

    static void Main(string[] args)
    {
        DerivedClass dc = new DerivedClass();
        BaseClass bcdc = new DerivedClass();

        dc.Write();
        bcdc.Write();

        Console.ReadKey(true);
    }

输出:

 Base - Method
 Base - Method

方法的IL代码Write

   .method public hidebysig instance void  Write() cil managed
   {
      // Code size       9 (0x9)
     .maxstack  8
     IL_0000:  nop
     IL_0001:  ldarg.0
     IL_0002:  callvirt   instance void Private_override.Program/BaseClass::Method()
     IL_0007:  nop
     IL_0008:  ret
   } // end of method BaseClass::Write

我不明白这里为什么Base调用方法。

这里 CLR 使用callvirt指令,这意味着它将查找调用变量类型,并且由于类型是DerivedClassDerivedClass隐藏的BaseClass.Method,因此应该只存在DerivedClass.Method于堆中的 DerivedClass 的 MethodTable 中。为什么BaseClass.Method叫?搜索方法时是否callvirt查找特定标志?override

4

2 回答 2

7

因为你没有override。更改newoverride,它将按照您讨论的方式运行(您也必须将可访问性更改为protected,否则将无法编译)。new创建一个恰好共享一个名称的不相关方法 - 它不是基类中其他同名方法的多态树的一部分。

你不妨问:“这个为什么不调用CompletelyDifferentName()?”

class BaseClass
{
    public void Write()
    {
        Method();
    }

    protected virtual void Method()
    {
        Console.WriteLine("Base - Method");
    }
}

class DerivedClass : BaseClass
{
    private void CompletelyDifferentName()
    {
        Console.WriteLine("Derived - Method");
    }
}

答案是一样的:与调用CompletelyDifferentName的(多态)方法没有任何关系。好吧,也没有- 这就是这里的意思virtualMethodnew void Method()new

于 2013-08-14T08:28:17.960 回答
1

因为这正是 new 应该如何工作。新意味着您的新方法与基类中同名的方法没有任何共同之处。这与在派生类方法中创建另一个名称相同,只是您使用相同的名称。即基类方法写入不会尝试调用新方法,因为它不是基类方法的新版本,它只是该类的另一个成员。

于 2013-08-14T10:56:50.960 回答