新的和覆盖的区别
想知道以下的区别是什么:
案例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 A
和B
, B
从A
inheritance,那么你实例化一个对象是这样的:
A a = new B();
现在调用方法将考虑到它的状态。 Override :意味着它扩展了方法的function,然后它使用派生类中的方法,而new则告诉编译器隐藏派生类中的方法,而不是使用基类中的方法。 这个主题非常好:
所有这些, 新是最混乱的。 通过实验,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"; } }