【问题标题】:What is the difference between the override and new keywords in C#?C# 中的 override 和 new 关键字有什么区别?
【发布时间】:2011-09-28 09:44:18
【问题描述】:

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

【问题讨论】:

    标签: c# .net oop


    【解决方案1】:

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

    Knowing When to Use Override and New Keywords

    总结

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

    新建:如果使用new关键字代替override,派生类中的方法不会覆盖基类中的方法,它只是隐藏它。

    如果您没有指定 new 或 overrides,则结果输出与您指定 new 时相同,但您也会收到编译器警告(因为您可能不知道您在基类方法,或者实际上您可能想要覆盖它,只是忘记包含关键字)。

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

    新增:当基类没有将方法声明为虚拟/抽象/覆盖时

    【讨论】:

    • 您能否在此处也包含重要信息。它有助于将信息保留在这里并防止链接失效(不太可能与 MSDN 博客,但你永远不知道)。
    • 大声笑“不太可能”我收到重定向,然后是“拒绝访问您没有查看/下载此项目的权限。”
    【解决方案2】:

    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;充其量是令人困惑的,因为您定义的方法的名称可能会被识别为其他东西,而在最坏的情况下,它可以隐藏错误,引入看似不可能的错误,并使扩展功能变得困难。

    【讨论】:

    • 这应该是公认的答案。它实际上通过示例解释了差异和含义。接受的答案非常模糊。
    • 在使用接口时会发生类似的情况(如 B 扩展 A,A 用Hello() 实现接口,将 B 分配给具有接口类型的变量)。最好在您的回答中澄清这一点,因为这就是我正在寻找的情况。
    【解决方案3】:

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

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

    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
      
      • 子类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
      【解决方案5】:

      override 允许您覆盖基类中的虚拟方法,以便您可以放入不同的实现。new 将隐藏基类中的非虚拟方法。

      【讨论】:

      • 我知道的就这么多了,但是 override 将有效地隐藏基类方法
      • 没有覆盖不会隐藏基类方法。 Override 将对基类方法的调用转换为对派生类方法的调用。在某种程度上,派生类中的方法与基类中的方法相同。而对于new,它是一个完全独立的方法,只是恰好具有相同的名称。
      • @CodeInChaos 感谢您说出我想说的比我能说的更好:)
      【解决方案6】:

      简单的区别在于override 表示该方法是虚拟的(它与基类中的virtual 关键字进行传导),而new 仅表示它不是虚拟的,它是一个常规覆盖。

      所以两者都是真正的函数覆盖,一个是具有虚拟特性的,另一个不是。

      具体是什么意思?它只是意味着多态性不会在“新”方法中发挥作用。

      下面的图片说明可能会清楚地说明这一点。

      注意如果你不使用new关键字,它仍然是隐含的,但它会产生一个警告信息。

      【讨论】:

        猜你喜欢
        • 2012-10-21
        • 2011-09-03
        • 2018-06-04
        • 2016-05-14
        • 1970-01-01
        • 2018-08-02
        • 2019-07-26
        相关资源
        最近更新 更多