想知道以下内容之间有什么区别:
情况1:基类
public void DoIt();
情况1:继承的类
public new void DoIt();
情况2:基类
public virtual void DoIt();
情况2:继承的类
public override void DoIt();
根据我运行的测试,案例1和案例2似乎具有相同的效果。有区别还是首选方式?
想知道以下内容之间有什么区别:
情况1:基类
public void DoIt();
情况1:继承的类
public new void DoIt();
情况2:基类
public virtual void DoIt();
情况2:继承的类
public override void DoIt();
根据我运行的测试,案例1和案例2似乎具有相同的效果。有区别还是首选方式?
Answers:
覆盖修饰符可用于虚拟方法,并且必须用于抽象方法。这指示编译器使用方法的最后定义的实现。即使该方法是在对基类的引用上调用的,它也将使用覆盖它的实现。
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
。
new修饰符指示编译器使用子类实现而不是父类实现。任何不引用您的类但父类的代码都将使用父类实现。
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
。实际上,它们是两个完全独立的方法,它们恰好具有相同的名称,而不是派生的方法覆盖基本方法。
资料来源:Microsoft网志
This indicates for the compiler to use the last defined implementation of a method
。如何找到方法的最后定义的实现?
override
当基类将方法定义为时,您才可以使用方法virtual
。这个词virtual
是基类,上面写着:“嘿,当我调用此方法时,它实际上可能已被派生的实现所替代,所以我事先并不真正知道我在运行时实际上在调用哪种方法。因此,virtual
表明–一个方法的占位符,这意味着未标记为的virtual
方法不能被覆盖,但是您可以用修饰符替换派生类中的任何非虚拟方法new
,只能在派生级别访问
在情况1中,如果您在将类型声明为基类时调用了继承类的DoIt()方法,则您甚至会看到基类的操作。
/* 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();
}
new
表示尊重您的REFERENCE类型()的左侧=
,从而运行引用类型的方法。如果重新定义的方法没有new
关键字,则其行为与原来相同。此外,它也称为非多态继承。也就是说,“我正在派生类中创建一个全新的方法,该方法与基类中同名的任何方法都完全没有关系。” -惠特克(Whitaker)说override
,必须virtual
在其基类中与关键字一起使用,表示要尊重您的OBJECT类型(的右侧=
),从而无论引用类型如何,都以覆盖的方式运行方法。此外,它也称为多态继承。
我要记住两个关键字彼此相反的方式。
override
:virtual
必须定义关键字以覆盖该方法。使用override
关键字的方法,无论引用类型(基类的引用还是派生类的引用)都被基类实例化,该方法都将运行基类的方法。否则,将运行派生类的方法。
new
:如果关键字是由方法使用的,则与override
关键字不同,引用类型很重要。如果使用派生类实例化它,并且引用类型是基类,则运行基类的方法。如果使用派生类实例化它,并且引用类型是派生类,则运行派生类的方法。即,是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
新的代码示例,
class X
{
protected internal /*virtual*/ void Method()
{
WriteLine("X");
}
}
class Y : X
{
protected internal /*override*/ void Method()
{
base.Method();
WriteLine("Y");
}
}
class Z : Y
{
protected internal /*override*/ void Method()
{
base.Method();
WriteLine("Z");
}
}
class Programxyz
{
private static void Main(string[] args)
{
X v = new Z();
//Y v = new Z();
//Z v = new Z();
v.Method();
}
我有同样的问题,这确实令人困惑,您应该考虑覆盖和新关键字仅适用于基类类型和派生类值的对象。在这种情况下,您只会看到override和new的效果:因此,如果您拥有class A
and B
,并且B
继承自A
,那么您将实例化这样的对象:
A a = new B();
现在,调用方法将考虑其状态。 覆盖:意味着它扩展了方法的功能,然后在派生类中使用该方法,而new告诉编译器在派生类中隐藏该方法,而在基类中使用该方法。这是一个很好的视野:
下面的文章在vb.net中,但是我认为关于新vs覆盖的解释非常容易理解。
https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides
在本文的某些时候,有这样的句子:
通常,Shadows假定调用了与该类型关联的功能,而Overrides假定执行了对象实现。
这个问题的公认答案是完美的,但是我认为本文提供了很好的示例,可以为这两个关键字之间的差异添加更好的含义。
在所有这些之中,新是最令人困惑的。通过实验,new关键字就像为开发人员提供了通过显式定义类型来用基类实现覆盖继承类实现的选项。就像在想另一种方式。
在下面的示例中,结果将返回“派生结果”,直到将类型显式定义为BaseClass test,然后才返回“基础结果”。
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";
}
}
在第一种情况下,它将调用派生类DoIt()方法,因为new关键字隐藏了基类DoIt()方法。
在第二种情况下,它将调用重写的DoIt()
public class A
{
public virtual void DoIt()
{
Console.WriteLine("A::DoIt()");
}
}
public class B : A
{
new public void DoIt()
{
Console.WriteLine("B::DoIt()");
}
}
public class C : A
{
public override void DoIt()
{
Console.WriteLine("C::DoIt()");
}
}
让我们创建这些类的实例
A instanceA = new A();
B instanceB = new B();
C instanceC = new C();
instanceA.DoIt(); //A::DoIt()
instanceB.DoIt(); //B::DoIt()
instanceC.DoIt(); //B::DoIt()
一切都在上面。让将instanceB和instanceC设置为instanceA并调用DoIt()方法并检查结果。
instanceA = instanceB;
instanceA.DoIt(); //A::DoIt() calls DoIt method in class A
instanceA = instanceC;
instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C