在类层次结构中定义方法时,C#中的override
和new
关键字有什么区别?
Answers:
下一页很好地总结了您的问题。
概要
重写:当派生类中重写基类的方法时,即使调用代码不“知道”该对象是派生类的实例,也将使用派生类中的版本。
新增:如果使用new关键字而不是override,则派生类中的方法不会覆盖基类中的方法,而只是将其隐藏。
如果您既不指定new也不重写,则输出结果与指定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分配给具有接口类型的变量)。最好在您的回答中阐明这一点,因为那是我一直在寻找的情况。
考虑以下类层次结构:
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
它是一个完全独立的方法,恰好具有相同的名称。