新的和覆盖的区别

想知道以下的区别是什么:

案例1:基础类

public void DoIt(); 

案例1:inheritance的类

 public new void DoIt(); 

案例2:基类

 public virtual void DoIt(); 

情况2:inheritance类

 public override void DoIt(); 

情况1和2似乎基于我已经运行的testing具有相同的效果。 有没有区别或者首选的方法?

override修饰符可以用于虚拟方法,并且必须用于抽象方法。 这表示编译器使用最后定义的方法实现。 即使该方法在对基类的引用上被调用,它也将使用覆盖它的实现。

 public class Base { public virtual void DoIt() { } } public class Derived : Base { public override void DoIt() { } } Base b = new Derived(); b.DoIt(); // Calls Derived.DoIt 

将调用Derived.DoIt如果这覆盖Base.DoIt

新的修饰符指示编译器使用您的子类实现,而不是父类实现。 任何不引用您的类,但父类的代码将使用父类的实现。

 public class Base { public virtual void DoIt() { } } public class Derived : Base { public new void DoIt() { } } Base b = new Derived(); Derived d = new Derived(); b.DoIt(); // Calls Base.DoIt d.DoIt(); // Calls Derived.DoIt 

首先会调用Base.DoIt ,然后Derived.DoIt 。 它们实际上是两个完全分离的方法,它们碰巧具有相同的名称,而不是派生方法重写基方法。

来源: 微软博客

virtual :表示一个方法可能被inheritance者重写

覆盖 :覆盖基类中虚拟方法的function,提供不同的function。

new隐藏原始方法(不必是虚拟的),提供不同的function。 这只能用在绝对必要的地方。

当你隐藏一个方法时,你仍然可以通过向上转换到基类来访问原始方法。 这在某些情况下很有用,但是很危险。

在第一种情况下,您将定义隐藏在父类中。 这意味着只有当您将对象作为子类处理时才会调用它。 如果您将该类转换为其父types,则将调用该父类的方法。 在第二个实例中,该方法被覆盖并将被调用,而不pipe该对象是否作为子类或父类被强制转换。

试试以下内容:(case1)

 ((BaseClass)(new InheritedClass())).DoIt() 

编辑:虚拟+覆盖在运行时解决(所以覆盖真的覆盖虚拟方法),而新的只是创build新的方法具有相同的名称,并隐藏旧的,这是在编译时parsing – >你的编译器将调用它的方法,看到

在情况1中,如果您使用的是inheritance类的DoIt()方法,而types被声明为基类,则甚至会看到基类的操作。

 /* Results Class1 Base1 Class2 Class2 */ public abstract class Base1 { public void DoIt() { Console.WriteLine("Base1"); } } public class Class1 : Base1 { public new void DoIt() { Console.WriteLine("Class1"); } } public abstract class Base2 { public virtual void DoIt() { Console.WriteLine("Base2"); } } public class Class2 : Base2 { public override void DoIt() { Console.WriteLine("Class2"); } } static void Main(string[] args) { var c1 = new Class1(); c1.DoIt(); ((Base1)c1).DoIt(); var c2 = new Class2(); c2.DoIt(); ((Base2)c2).DoIt(); Console.Read(); } 

两种情况的不同之处在于,情况1中, DoIt方法不会被覆盖,只是隐藏起来。 这意味着取决于variables的types取决于调用哪个方法。 例如:

 BaseClass instance1 = new SubClass(); instance1.DoIt(); // Calls base class DoIt method SubClass instance2 = new SubClass(); instance2.DoIt(); // Calls sub class DoIt method 

这可能会令人困惑,并导致非预期的行为,应尽可能避免。 所以最好的办法是情况2。

如果在派生类中使用关键字override ,则覆盖父方法。

如果在派生类中使用关键字new ,则派生方法由父方法隐藏。

我的方法要牢记两个关键字,他们是相反的。

override :必须定义virtual关键字来覆盖该方法。 使用override关键字的方法,不pipe引用types(基类或派生类的引用),如果用基类实例化,基类的方法运行。 否则,派生类的方法运行。

new :如果关键字被方法使用,与override关键字不同,则引用types很重要。 如果使用派生类实例化,并且引用types是基类,则运行基类的方法。 如果使用派生类实例化,并且引用types是派生类,则派生类的方法将运行。 也就是说,这是override关键字的对比。 顺便说一下,如果您忘记或省略了将新关键字添加到方法中,编译器默认使用new关键字。

 class A { public string Foo() { return "A"; } public virtual string Test() { return "base test"; } } class B: A { public new string Foo() { return "B"; } } class C: B { public string Foo() { return "C"; } public override string Test() { return "derived test"; } } 

主要呼叫:

 A AClass = new B(); Console.WriteLine(AClass.Foo()); B BClass = new B(); Console.WriteLine(BClass.Foo()); B BClassWithC = new C(); Console.WriteLine(BClassWithC.Foo()); Console.WriteLine(AClass.Test()); Console.WriteLine(BClassWithC.Test()); 

输出:

 A B B base test derived test 

下面的文章是在vb.net中,但我认为关于新的vs overrides的解释很容易理解。

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

在文章的某一点,有这样一句话:

一般来说,Shadows假定与该types关联的函数被调用,而Overrides假定对象实现被执行。

这个问题被接受的答案是完美的,但我认为这篇文章提供了很好的例子,为这两个关键字之间的差异添加更好的意义。

这些testing中不会显示function差异:

 BaseClass bc = new BaseClass(); bc.DoIt(); DerivedClass dc = new DerivedClass(); dc.ShowIt(); 

在这个例子中,所谓的Doit就是你期望被称为的Doit。

为了看到不同,你必须这样做:

 BaseClass obj = new DerivedClass(); obj.DoIt(); 

你会看到,如果你运行testing(如你所定义的DoIt()BaseClass中调用DoIt() ,在情况2中(如你所定义的), DoIt()

我有同样的问题,它真的很混乱,你应该考虑覆盖新的关键字只能用于基类和派生类的值的对象。 在这种情况下,只有你会看到覆盖和新的效果:所以如果你有class ABBAinheritance,那么你实例化一个对象是这样的:

 A a = new B(); 

现在调用方法将考虑到它的状态。 Override :意味着它扩展了方法的function,然后它使用派生类中的方法,而new则告诉编译器隐藏派生类中的方法,而不是使用基类中的方法。 这个主题非常好:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396

所有这些, 是最混乱的。 通过实验,new关键字就像给开发人员提供了通过显式定义types来覆盖基类实现的inheritance类实现的选项。 这就像是在想另一种方式。

在下面的例子中,结果将返回“派生结果”,直到types明确定义为BaseClasstesting,只有“基础结果”将被返回。

 class Program { static void Main(string[] args) { var test = new DerivedClass(); var result = test.DoSomething(); } } class BaseClass { public virtual string DoSomething() { return "Base result"; } } class DerivedClass : BaseClass { public new string DoSomething() { return "Derived result"; } }