C#中override和new关键字有什么区别?

86

在类层次结构中,使用 overridenew 关键字定义方法的区别是什么?

6个回答

117
以下页面很好地总结了您的问题。 知道该何时使用 Override 和 New 关键字 概述 Override: 当在派生类中覆盖基类的方法时,即使调用代码不知道对象是派生类的实例,也将使用派生类中的版本。 New: 如果使用 new 关键字而不是 override,则派生类中的方法不会覆盖基类中的方法,而只是隐藏它。 如果既不指定 new 也不指定 override,则生成的输出与指定 new 相同,但您也会收到编译器警告(因为您可能不知道正在隐藏基类方法,或者确实想要覆盖它,只是忘记包括关键字)。 Override: 与基类中的 virtual/abstract/override 类型的方法一起使用。 New: 当基类未将方法声明为 virtual/abstract/override 时。

11
请问您能否同时在这里包含关键信息呢?这将有助于保留信息并防止链接失效(虽然 MSDN 博客很少出现这种情况,但谨慎起见)。请注意不要改变原意,尽可能使表述通俗易懂。 - ChrisF
4
“unlikely” 表示不太可能,而后面的 “Access Denied You do not have permission to view/download this item.” 则是指没有访问权限,无法查看或下载该物品。 - tobsen

88

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可用。当父对象的方法、属性、字段或事件没有声明为virtual时,可以使用new,由于缺乏virtual,编译器不会“查找”继承的方法。但是,使用virtualoverride就能够解决这个问题。
我强烈建议您避免使用new;在最好的情况下,它很令人困惑,因为您正在定义一个可能被认为是其他东西的名称的方法,而在最坏的情况下,它可能会隐藏错误、引入看似不可能的错误,并使扩展功能变得困难。

16
这应该成为被认可的答案。它用例子解释了差异和含义,更易理解。被认可的答案比较笼统。 - theyetiman
1
当使用接口时(例如B扩展A,A实现具有“Hello()”的接口,将B分配给具有接口类型的变量),类似的情况会发生。在您的答案中澄清这一点也是很好的,因为这就是我正在寻找的情况。 - ahong

10

看起来这是一个老问题,让我尝试不同的回答:

  1. new :如其名,它是继承层次结构中的一个新成员,并且如果标记为virtual,则将用作进一步向下链的基础成员。

  2. override :它意味着我不接受我的父类成员实现,我会做出不同的实现。


4
考虑以下类层次结构:
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
  • 子类通过应用override修饰符来覆盖虚方法:
  • 如果您想有意地隐藏一个成员,那么您可以在子类中对该成员应用new修饰符new修饰符仅仅是抑制编译器会产生的警告

1
好的例子,我认为如果您将 Program 类和其他类拆分为两个单独的代码块,并将输出与方法调用一起作为注释,例如 base2.Foo(); // Base => Foo,它将更易读。我还会省略命名空间和导入,但如果您想提供可运行的代码,则只需链接到 https://dotnetfiddle.net/。 - ahong

2

override允许你重写基类中的虚方法,以便你可以放置不同的实现。而new则会隐藏基类中的非虚方法。


我知道这些,然而,覆盖会有效地隐藏基类的方法。 - jaywayco
2
不重写并不会隐藏基类方法。重写将对基类方法的调用转换为对派生类方法的调用。使用重写,派生类中的方法与基类中的方法是相同的。而使用 new 则是完全独立的方法,只是恰好具有相同的名称。 - CodesInChaos
@CodeInChaos 谢谢您说得比我表达得更好 :) - Daniel Mann

1
简单的区别在于`override`表示该方法是虚拟的(与基类中的`virtual`关键字一起使用),而`new`仅表示它不是虚拟的,它是一个常规覆盖。
因此,两者都是函数重写,一个具有虚拟特性,另一个没有。
这到底意味着什么?这意味着对于“新”的方法,多态性将不会发挥作用。
下面的图像说明可能会使这一点清晰。

enter image description here

请注意,如果您不使用new关键字,它仍然会被暗示,但会生成警告消息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接