我对新关键字感到困惑,当我使用虚拟和覆盖时,工作正常,但与新的有点不同(我想我错过了一些东西)
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. 所以,在我出错的地方,似乎是一个愚蠢的错误: - )
答案 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)
基本上,一旦您创建了派生自A
或B
的其他类,您就会发现调用base.Test()
会为这些类调用A
的版本其中override
而不是new
以及B
派生的B
版本会被调用A
,但不会{{1}}。
答案 3 :(得分:0)
“新”表示方法是“新”而不是“替代”。因此,如果您从基数中使用该名称调用方法,则该方法不会被覆盖,因此不会调用派生方法。