215

在基类型“”中声明一个方法,virtual然后在子类型中使用“”关键字覆盖它,而不是在子类型中声明匹配方法时override简单地使用“ ”关键字有什么区别?new

4

11 回答 11

242

我总是发现用图片更容易理解这样的事情:

再次,采用约瑟夫戴格尔的代码,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

如果你然后这样调用代码:

Foo a = new Bar();
a.DoSomething();

注意:重要的是我们的对象实际上是 a Bar,但是我们将它存储在一个类型的变量中Foo(这类似于强制转换它)

然后结果将如下所示,具体取决于您是否使用virtual/overridenew在声明您的类时。

虚拟/覆盖说明图像

于 2008-10-01T22:41:29.277 回答
192

“new”关键字不会覆盖,它表示一个与基类方法无关的新方法。

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

这将打印为 false,如果您使用覆盖,它将打印为 true。

(取自 Joseph Daigle 的基本代码)

所以,如果你在做真正的多态,你应该总是 OVERRIDE。唯一需要使用“new”的地方是该方法与基类版本没有任何关系。

于 2008-10-01T22:10:01.223 回答
46

下面是一些代码来理解虚拟和非虚拟方法的行为差异:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}
于 2008-10-01T22:15:01.680 回答
20

new关键字实际上创建了一个仅存在于该特定类型上的全新成员。

例如

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

该方法存在于两种类型上。当您使用反射并获取 type 的成员时Bar,您实际上会发现 2 个调用DoSomething()的方法看起来完全一样。通过使用new,您可以有效地隐藏基类中的实现,以便当类从Bar(在我的示例中)派生时,方法调用base.DoSomething()转到Bar而不是Foo

于 2008-10-01T22:10:18.150 回答
11

除了技术细节之外,我认为使用 virtual/override 可以在设计上传达很多语义信息。当您声明一个虚拟方法时,您表明您希望实现类可能希望提供它们自己的非默认实现。同样,在基类中省略它,声明了默认方法应该足以满足所有实现类的期望。类似地,可以使用抽象声明来强制实现类提供它们自己的实现。同样,我认为这传达了很多关于程序员期望如何使用代码的信息。如果我同时编写基类和实现类并且发现自己使用 new 我会认真重新考虑不在父类中使方法为虚拟的决定并明确声明我的意图。

于 2008-10-01T22:20:31.963 回答
10

virtual / override告诉编译器这两个方法是相关的,并且在某些情况下,当您认为您正在调用第一个(虚拟)方法时,实际上调用第二个(覆盖)方法是正确的。这是多态性的基础。

(new SubClass() as BaseClass).VirtualFoo()

将调用子类的重写 VirtualFoo() 方法。

new告诉编译器您正在向派生类添加一个与基类中的方法同名的方法,但它们彼此没有关系。

(new SubClass() as BaseClass).NewBar()

将调用 BaseClass 的 NewBar() 方法,而:

(new SubClass()).NewBar()

将调用子类的 NewBar() 方法。

于 2008-10-01T22:24:02.517 回答
4

override关键字和new关键字的区别在于前者做方法覆盖,后者做方法隐藏。

查看以下链接以获取更多信息...

MSDN其他

于 2008-10-01T22:11:50.923 回答
3
  • new关键字用于隐藏。- 表示您在运行时隐藏您的方法。输出将基于基类方法。
  • override为压倒一切。- 表示您正在使用基类的引用调用派生类方法。输出将基于派生类方法。
于 2011-07-19T06:51:47.620 回答
1

我的解释版本来自使用属性来帮助理解差异。

override很简单,对吧?基础类型覆盖父类型。

new也许是误导(对我来说是这样)。使用属性更容易理解:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

使用调试器你会注意到它Foo foo2 个 GetSomething属性,因为它实际上有 2 个版本的属性,Foo's 和Bar's,并且要知道要使用哪一个,c#“选择”当前类型的属性。

如果你想使用 Bar 的版本,你会使用 override 或 useFoo foo代替。

Bar bar只有1,因为它想要全新的行为GetSomething

于 2016-09-06T07:30:48.733 回答
1

不使用任何方法标记方法意味着:使用对象的编译类型绑定此方法,而不是运行时类型(静态绑定)。

使用方法标记方法virtual:使用对象的运行时类型绑定此方法,而不是编译时类型(动态绑定)。

在派生类中标记基类virtual方法override意味着:这是使用对象的运行时类型绑定的方法(动态绑定)。

在派生类中标记基类virtual方法new意味着:这是一个新方法,与基类中的同名方法没有关系,应该使用对象的编译时类型(静态绑定)进行绑定。

在派生类中不标记基类virtual方法意味着:这个方法被标记为new(静态绑定)。

标记一个方法abstract意味着:这个方法是虚拟的,但我不会为它声明一个主体,它的类也是抽象的(动态绑定)。

于 2018-12-05T19:59:34.197 回答
1
using System;  
using System.Text;  
  
namespace OverrideAndNew  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            BaseClass bc = new BaseClass();  
            DerivedClass dc = new DerivedClass();  
            BaseClass bcdc = new DerivedClass();  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in BaseClass.  
            bc.Method1();  
            bc.Method2();  
            // Output:  
            // Base - Method1  
            // Base - Method2  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in DerivedClass.  
            dc.Method1();  
            dc.Method2();  
            // Output:  
            // Derived - Method1  
            // Derived - Method2  
  
            // The following two calls produce different results, depending
            // on whether override (Method1) or new (Method2) is used.  
            bcdc.Method1();  
            bcdc.Method2();  
            // Output:  
            // Derived - Method1  
            // Base - Method2  
        }  
    }  
  
    class BaseClass  
    {  
        public virtual void Method1()  
        {  
            Console.WriteLine("Base - Method1");  
        }  
  
        public virtual void Method2()  
        {  
            Console.WriteLine("Base - Method2");  
        }  
    }  
  
    class DerivedClass : BaseClass  
    {  
        public override void Method1()  
        {  
            Console.WriteLine("Derived - Method1");  
        }  
  
        public new void Method2()  
        {  
            Console.WriteLine("Derived - Method2");  
        }  
    }  
}  
于 2021-06-30T10:17:30.330 回答