【发布时间】:2011-09-28 09:44:18
【问题描述】:
在类层次结构中定义方法时,C# 中的override 和new 关键字有什么区别?
【问题讨论】:
在类层次结构中定义方法时,C# 中的override 和new 关键字有什么区别?
【问题讨论】:
以下页面很好地总结了您的问题。
Knowing When to Use Override and New Keywords
总结
重写:当基类的方法在派生类中被重写时,将使用派生类中的版本,即使调用代码不“知道”该对象是派生类的一个实例。
新建:如果使用new关键字代替override,派生类中的方法不会覆盖基类中的方法,它只是隐藏它。
如果您没有指定 new 或 overrides,则结果输出与您指定 new 时相同,但您也会收到编译器警告(因为您可能不知道您在基类方法,或者实际上您可能想要覆盖它,只是忘记包含关键字)。
覆盖:与基类中的虚拟/抽象/覆盖类型的方法一起使用
新增:当基类没有将方法声明为虚拟/抽象/覆盖时
【讨论】:
new 将使用全新的方法(可能具有或不具有相同的签名)覆盖该方法,而不是覆盖它(在这种情况下,新方法必须具有相同的签名),这意味着多态不会工作。例如,您有这些类:
class A {
public virtual int Hello() {
return 1;
}
}
class B : A {
new public int Hello(object newParam) {
return 2;
}
}
class C : A {
public override int Hello() {
return 3;
}
}
如果你这样做:
A objectA;
B objectB = new B();
C objectC = new C();
Console.WriteLine(objectB.Hello(null)); // 2
Console.WriteLine(objectC.Hello()); // 3
objectA = objectB;
Console.WriteLine(objectA.Hello()); // 1
objectA = objectC;
Console.WriteLine(objectA.Hello()); // 3
由于您可以使用new 定义新方法签名,因此编译器不可能知道A 的实例实际上是B 的实例,并且应该可以使用新方法B 定义。 new 可以在父对象的方法、属性、字段或事件未使用virtual 声明时使用,并且由于缺少virtual,编译器不会“查找”继承的方法。但是,对于 virtual 和 override,它可以工作。
我强烈建议您避免使用new;充其量是令人困惑的,因为您定义的方法的名称可能会被识别为其他东西,而在最坏的情况下,它可以隐藏错误,引入看似不可能的错误,并使扩展功能变得困难。
【讨论】:
Hello() 实现接口,将 B 分配给具有接口类型的变量)。最好在您的回答中澄清这一点,因为这就是我正在寻找的情况。
看起来像一个老问题,让我尝试一个不同的答案:
new :顾名思义,它是继承层次结构家族中的一个新成员,它将用作更下游的基础成员(如果标记为虚拟)。
override :这意味着我不接受我的父类的成员实现,我会做不同的事情。
【讨论】:
考虑以下类层次结构:
using System;
namespace ConsoleApp
{
public static class Program
{
public static void Main(string[] args)
{
Overrider overrider = new Overrider();
Base base1 = overrider;
overrider.Foo();
base1.Foo();
Hider hider = new Hider();
Base base2 = hider;
hider.Foo();
base2.Foo();
}
}
public class Base
{
public virtual void Foo()
{
Console.WriteLine("Base => Foo");
}
}
public class Overrider : Base
{
public override void Foo()
{
Console.WriteLine("Overrider => Foo");
}
}
public class Hider : Base
{
public new void Foo()
{
Console.WriteLine("Hider => Foo");
}
}
}
以上代码的输出必须是:
Overrider => Foo
Overrider => Foo
Hider => Foo
Base => Foo
- 子类
overrides通过应用override modifier实现虚方法:- 如果你想故意
hide一个成员,在这种情况下你可以将new modifier应用于子类中的成员。The new modifier does nothing more than suppress the compiler warning that would otherwise result
【讨论】:
Program 类和其他类分成两个单独的代码块,输出与方法调用内联作为注释,例如base2.Foo(); // Base => Foo。我也会省略命名空间和导入,但如果你想提供可运行的代码,那么只需链接到 dotnetfiddle.net
override 允许您覆盖基类中的虚拟方法,以便您可以放入不同的实现。new 将隐藏基类中的非虚拟方法。
【讨论】:
new,它是一个完全独立的方法,只是恰好具有相同的名称。