在基本类型“virtual”中声明一个方法,然后在子类型中使用“override”关键字重写它,与在子类型中声明匹配的方法时简单地使用“new”关键字相比,两者之间有什么区别?


当前回答

“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,如果你使用override,它会输出true。

(基本代码取自Joseph Daigle)

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

其他回答

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");  
        }  
    }  
}  

“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,如果你使用override,它会输出true。

(基本代码取自Joseph Daigle)

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

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

例如

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

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

该方法存在于这两种类型上。当您使用反射并获取Bar类型的成员时,您实际上会发现两个称为DoSomething()的方法看起来完全相同。通过使用new,你可以有效地将实现隐藏在基类中,这样当类从Bar派生出来时(在我的例子中),对base. dosomething()的方法调用就会到Bar而不是Foo。

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

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;
    }
}

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

重写很简单,对吧?底层类型覆盖父类型。

新可能是误导(对我来说是)。使用属性更容易理解:

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 Foo有两个GetSomething属性,因为它实际上有两个版本的属性,Foo's和Bar's,为了知道使用哪个,c#“选择”当前类型的属性。

如果你想使用Bar的版本,你应该使用override或使用Foo Foo代替。

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