在声明子类型中的匹配方法时,使用基本类型“ virtual”声明方法,然后使用“ override”关键字在子类型中重写该方法,而不是简单地使用“ new”关键字,有什么区别?

评论

MSDN说:“使用new创建具有相同名称的新成员并导致原始成员被隐藏,而重写将继承的成员的实现扩展”。

看到这个stackoverflow.com/questions/17717570/…

MSDN-msdn.microsoft.com/zh-CN/library/ms173153.aspx

#1 楼

“ 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的基本代码)

因此,如果您要执行真正的多态性,则应始终覆盖。您唯一需要使用“ new”的地方是该方法与基类版本没有任何关系。

评论


您应该修改您的代码,因为我已经将方法设为静态(对于使用“ new”关键字有效)。但是我认为使用实例方法更加清晰。

–约瑟夫·戴格(Joseph Daigle)
08年10月1日在22:16

谢谢,我错过了“静态”部分。未来应多加注意

– albertein
08年10月1日在22:17

请注意,这里的Foo test = new Bar()行非常关键,当将Bar放入Foo变量中时,metods的new / override关键字确定调用哪个metod。

–托马斯N
2015年4月20日的13:00

...因此,这与在基类中不包含虚拟对象并在派生类中覆盖替代对象完全相同?为什么存在?即使没有新代码,代码也将继续运行-因此,它仅仅是可读性吗?

–唐·奇德尔(Don Cheadle)
15年6月22日在22:22



亲爱的先生,您的回答很含糊。 new和virtual-override做相同的事情,唯一的不同是new HIDES父类中的方法并重写..很好,重写了它。当然,它会输出false,因为您的测试对象的类型为Foo,如果它的类型为Bar,则它的结果为true。不过,这个例子很棘手。

– MrSilent
2015年8月5日在16:49



#2 楼

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

,再次以约瑟夫·戴格尔的代码为例,

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();


注意:重要的是我们的对象实际上是Bar,但是我们将其存储在Foo类型的变量中(类似于

然后结果将如下所示,具体取决于在声明类时使用的是virtual / override还是new



评论


谢谢....但是您能不能对您所说的演员表解释一下上面的图片?

–odiseh
09年7月2日在11:30

糟糕,如果忘记将这几行添加到我的上一页。评论:您是说虚拟/覆盖和非虚拟/新仅用于多态概念,而当您简单地声明一个变量(不使用强制转换)时,它们并不意味着?再次感谢。

–odiseh
09年7月2日在11:35

真正努力回答这个问题。

– iMatoria
2011年7月21日,下午3:33

#3 楼

以下是一些代码,可以了解虚拟方法和非虚拟方法的行为差异:

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


评论


谢谢你-但是当不使用覆盖似乎可以做到这一点时,为什么要使用new来“隐藏”基本方法呢?

–唐·奇德尔(Don Cheadle)
15年6月22日在22:01

我不认为创建它是为了防止基类被覆盖。我认为它是为了避免名称冲突而创建的,因为您无法覆盖非虚拟的方法,并且如果在没有虚拟签名的类“ bloodline”上看到相同的函数名称,编译器将抱怨

–mr5
17-6-27 at 10:26



#4 楼

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

例如

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

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


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

#5 楼

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

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


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

new告诉编译器您要添加派生类的方法,其名称与基类中的方法相同,但彼此之间没有关系。

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


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

(new SubClass()).NewBar()


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

评论


真的很喜欢这句话“告诉编译器”

– Mina Gabriel
15年3月26日在22:31

“多态性的基础”是另一种经典的说法:)

–杰里米·汤普森(Jeremy Thompson)
17年1月1日在6:44

#6 楼

除了技术细节之外,我认为使用虚拟/覆盖可以传达设计上的许多语义信息。在将方法声明为虚拟方法时,表示您希望实现类可能希望提供自己的非默认实现。同样,在基类中省略此方法,则声明期望默认方法应足以满足所有实现类。同样,可以使用抽象声明来强制实现类提供自己的实现。同样,我认为这传达了很多关于程序员期望代码使用方式的信息。如果我同时编写了基类和实现类,并且发现自己使用的是新的类,那么我将认真考虑是否不要在父级中使该方法虚拟化并明确声明我的意图的决定。

评论


关于新vs覆盖的技术解释是正确的,但是这个答案似乎最能指导开发人员使用。

–真的
2014-02-26 14:21

#7 楼

Override关键字和new关键字之间的区别在于,前者执行方法重写,而后者执行方法隐藏。

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

MSDN和其他

#8 楼



new关键字用于隐藏。 -表示您在运行时隐藏了方法。输出将基于基类方法。

override用于覆盖。 -表示您正在使用基类的引用来调用派生类的方法。输出将基于派生类方法。


#9 楼

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

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 foo具有2个GetSomething属性,因为它实际上具有2个版本的属性Foo,和Bar,并知道要使用哪一个,c#会“挑选”当前类型的属性。

如果要使用Bar的版本,则应使用覆盖或改用Foo foo

Bar bar只有1,因为它希望GetSomething具有全新的行为。 br />

#10 楼

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

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

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

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

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

标记方法abstract的意思是:该方法是虚拟的,但我不会为其声明主体,并且其类也是抽象的(动态绑定)。