`CallVirt`和`New`关键字

时间:2013-08-14 08:13:28

标签: c# .net oop clr

此问题与How CLR calls methods correctly hidden by derived class when reference is stored in a base class variable?

相关联

在我的情况下,我使用的是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

Write方法的IL代码:

   .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的MethodTable中为DerivedClass.Method。为什么调用BaseClass.Methodcallvirt在搜索方法时会查找特定的override标记吗?

2 个答案:

答案 0 :(得分:7)

因为你没有override它。将new更改为override,它会按照您的讨论行事(您必须将可访问性更改为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与名为virtual的{​​{1}}(多态)方法没有任何关系。好吧,Method也没有 - 这就是new void Method() 的含义

答案 1 :(得分:1)

因为这正是新的应该如何运作。 New表示新方法与基类中具有相同名称的方法没有任何共同之处。 它与使用其他名称在派生类方法中创建相同,只是使用相同的名称。 即基类方法write不会尝试调用new方法,因为它不是基类中Method的新版本,它只是该类的另一个成员。