新关键字在派生类中的工作原理

时间:2010-02-22 18:18:03

标签: c# new-operator shadowing

我对新关键字感到困惑,当我使用虚拟和覆盖时,工作正常,但与新的有点不同(我想我错过了一些东西)

 class A
{
    public virtual void Test()
    {
        Console.WriteLine("I am in A");
    }
}

class B:A
{
    public override void Test()
    {
        Console.WriteLine("I am in B");
    }
}


class Program
{
    static void Main(string[] args)
    {
        B b = new B();
        b.Test(); //I am in B
        A a = new B();
        Console.WriteLine(a.GetType()); // Type-B
        a.Test(); //I am in B
       Console.ReadKey();
    }
}

}

现在有了新的

class A
{
    public  void Test()
    {
        Console.WriteLine("I am in A");
    }
}

class B:A
{
    public new void Test()
    {
        Console.WriteLine("I am in B");
    }
}


class Program
{
    static void Main(string[] args)
    {
        B b = new B();
        b.Test(); //I am in B
        A a = new B();
        Console.WriteLine(a.GetType()); //B
        a.Test(); // I am in A ? why?
       Console.ReadKey();
    }
}

根据MSDN使用new关键字时,将调用新的类成员而不是已替换的基类成员。这些基类成员称为隐藏成员,GetType()也显示类型为B. 所以,在我出错的地方,似乎是一个愚蠢的错误: - )

4 个答案:

答案 0 :(得分:2)

查看new关键字用法的Jon Skeet's descriptio n。因为a被转换为A,所以你调用A的方法,该方法无法被覆盖。 B碰巧有一个同名的方法。

答案 1 :(得分:2)

使用new关键字隐藏基类方法时,编译器会解析调用,而不是在运行时。

因此,当您编写a.Test时,编译器会在Test类上调用A方法。即使a变量恰好引用B实例,编译器也不关心,它仍然调用A上的版本。

当您调用虚方法时,编译器会发出callvirt指令,告诉运行时根据实例的实际类型找到正确的调用方法。运行时知道该实例实际上是B类型,并且会看到B覆盖该方法并调用被覆盖的版本。

答案 2 :(得分:0)

基本上,一旦您创建了派生自AB的其他类,您就会发现调用base.Test()会为这些类调用A的版本其中override而不是new以及B派生的B版本会被调用A,但不会{{1}}。

答案 3 :(得分:0)

  

“新”表示方法是“新”而不是“替代”。因此,如果您从基数中使用该名称调用方法,则该方法不会被覆盖,因此不会调用派生方法。