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


75

在类层次结构中定义方法时,C#中的overridenew关键字有什么区别?

Answers:


101

下一页很好地总结了您的问题。

知道何时使用替代和新关键字

概要

重写:当派生类中重写基类的方法时,即使调用代码不“知道”该对象是派​​生类的实例,也将使用派生类中的版本。

新增:如果使用new关键字而不是override,则派生类中的方法不会覆盖基类中的方法,而只是将其隐藏。

如果您既不指定new也不重写,则输出结果与指定new相同,但是还会收到编译器警告(因为您可能不知道自己在基类中隐藏了一个方法方法,或者实际上您可能想覆盖它,而只是忘记了包含关键字)。

覆盖:与基类中的虚拟/抽象/覆盖类型的方法一起使用

新建:当基类未将方法声明为虚拟/抽象/覆盖时


9
您能否在这里也包括重要信息。它有助于将信息保存在此处,并防止链接腐烂(与MSDN博客不同,但您永远不会知道)。
克里斯·

3
大声笑“不太可能”,我得到一个重定向,然后是“访问被拒绝,您没有查看/下载此项目的权限”。
tobsen

78

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编译器而无法“查找”继承的方法。使用virtualoverride,它可以工作。

我强烈建议你避免new; 充其量是令人困惑的,因为您正在定义一个名称可以被识别为其他名称的方法,最糟糕的是,它可能隐藏错误,引入看似不可能的错误以及使功能扩展变得困难。


14
这应该是公认的答案。它实际上通过示例解释了差异和含义。公认的答案很模糊。
theyetiman 2015年

使用接口时会发生类似的情况(例如在B扩展A中,A使用实现了接口Hello(),将B分配给具有接口类型的变量)。最好在您的回答中阐明这一点,因为那是我一直在寻找的情况。
阿旬

9

看起来像个老问题,让我尝试不同的答案:

  1. new :顾名思义,它是继承层次结构家族中的一个新成员,它将用作基础成员,以进一步扩展该链(如果标记为虚拟)。

  2. override :这意味着我不接受父类的成员实现,并且我会做不同的事情。


3

考虑以下类层次结构:

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
阿旬

1

override允许您在基类中重写虚拟方法,以便可以放入其他实现。new将在基类中隐藏非虚拟方法。


但是我知道,重写将有效地隐藏一个基类方法
jaywayco 2011年

2
没有覆盖不会隐藏基类方法。重写将对基类方法的调用转换为对派生类方法的调用。在某种程度上,派生类中的方法与基类中的方法相同。而new它是一个完全独立的方法,恰好具有相同的名称。
CodesInChaos 2011年

@CodeInChaos感谢您说出我想说的要比我能说的要好的东西:)
Daniel Mann
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.