C# New关键字:为什么不调用派生方法?

C# New关键字:为什么不调用派生方法?,c#,inheritance,C#,Inheritance,我有三个简单的课程: class A { public virtual void Write() { Console.Write("A"); } } class B:A { public override void Write() { Console.Write("B"); } } class C : B { public new void Write() { Console.Wr

我有三个简单的课程:

class A
{
    public virtual void Write()
    {
        Console.Write("A");
    }
}

class B:A
{
    public override void Write()
    {
        Console.Write("B");
    }
}

class C : B
{
    public new void Write()
    {
        Console.Write("C");
    }
}
我正在创建对象并调用它们的方法:

A a = new A();
a.Write();

A b = new C();
b.Write();

C c = new C();
c.Write();
输出为:
ABC

我无法理解的是为什么这些代码会产生
B

A b = new C();
b.Write();
我想应该是
C
。但是,我测试了很多次,它总是
B

我理解
ab=newc()
创建了C的新对象类型。所以输出应该是C。或者,当我们使用重写方法而不强制转换时,调用重写方法是一种特殊行为


为什么会这样?因为我们没有使用任何对
B
类的引用。

如果您使用
((C)B)。Write()

使用
new
关键字并不是覆盖C的
Write
方法,而是创建一个只为C定义的新方法。因此,对于C,实际上有两个方法名为
Write

A c = new C();

c.Write();          //Output "B", you're calling the overridden method    
((C)c).Write();     //Output "C", you're calling the method defined on C

//or

(c as C).Write();
当您将c定义为
c
时,也会发生同样的情况:

C c = new C();

c.Write();          //Output "C"    
((A)c).Write();     //Output "B"
在第一个示例中,您正在调用C上定义的新方法。在第二行中,您正在从A调用
Write
方法,该方法被B覆盖,因此输出
“B”

编辑:(更多说明)


变量
c
的类型是A,因此编译器知道“c是A的实例”,但不知道它实际上是更派生的类型。当您在其上调用方法
Write
时,它将调用在A上定义的方法(由B覆盖)。您的基类A不知道您在C上定义的新方法(这就是
new
所做的,创建一个新方法),因此除非您将它转换为C,让编译器知道
C
的实际派生类型,否则将调用基类的方法。

我现在已经很晚了,没有回答这个问题,但我需要这种行为,以防万一其他人需要,我会分享它。 例如,要获得beheavior,您需要使用接口

interface Writer{
 void write;
}

class A : Writer
{
    void Writer.Write()
    {
        Console.Write("A");
    }
}
其他的也一样。正如您所看到的,您必须实现它的显式性,并将其称为显式

A c = new C();
((Writer) c).write()

)

因为这就是新关键字的工作原理。通常被称为“成员隐藏”或“隐藏”,谨慎使用它-当您期望代码执行其他操作时,它可能会非常刺耳。我很抱歉我的愚蠢问题,但是为什么这些代码
ab=new C();b、 Write()调用重写的方法?我的意思是
ab=newc()
创建
C
的新对象类型。所以输出应该是
C
。或者,当我们在不强制转换的情况下使用重写方法时,调用重写方法是一种特殊行为?要访问隐藏另一个方法的方法,需要对定义隐藏的类型的强类型引用,而不是基引用。同样的规则也适用于显式实现的接口。它基本上不是“正确的”继承,因此继承层次结构的实施方式与标准重写方法调用的方式不同。很难解释,但你说你的变量
c
a
类型,所以你的编译器知道“c是a的一个实例”,不知道它实际上是更派生的类型。当您在其上调用方法
Write
时,它将调用在A上定义的方法,该方法实际上被B覆盖。您的基类
A
不知道在C上定义的新方法(与
WriteLine
方法完全相同,
new
就是这样做的,创建一个新方法),因此,除非您将其强制转换为
C
,否则将调用基类的方法。@Steppup在中编辑了它:)