C# 不带“virtual”的基本方法与带“virtual”的基本方法以及带“new”的派生方法?
我正在尝试理解新的虚拟方法 以下两种方式的区别是什么:C# 不带“virtual”的基本方法与带“virtual”的基本方法以及带“new”的派生方法?,c#,C#,我正在尝试理解新的虚拟方法 以下两种方式的区别是什么: 在基类中定义一个不带virtual的方法,并在子类中定义一个具有相同名称和签名的方法 使用virtual在基类中定义方法,并在子类中定义具有相同名称和签名以及new的方法 如果它们不同,为什么在下面的示例中它们的行为相同 using System; public class Base { public void DoIt() { Console.WriteLine ("Base: DoIt"); }
- 在基类中定义一个不带
的方法,并在子类中定义一个具有相同名称和签名的方法virtual
- 使用
在基类中定义方法,并在子类中定义具有相同名称和签名以及virtual
的方法new
using System;
public class Base
{
public void DoIt()
{
Console.WriteLine ("Base: DoIt");
}
public virtual void DoItVirtual1()
{
Console.WriteLine ("Base: DoItVirtual1");
}
public virtual void DoItVirtual2()
{
Console.WriteLine ("Base: DoItVirtual2");
}
}
public class Derived : Base
{
public void DoIt()
{
Console.WriteLine ("Derived: DoIt");
}
public override void DoItVirtual1()
{
Console.WriteLine ("Derived: DoItVirtual1");
}
public new void DoItVirtual2()
{
Console.WriteLine ("Derived: DoItVirtual2");
}
}
class MainClass {
public static void Main (string[] args) {
Base b = new Base();
Derived d = new Derived();
Base bd = new Derived();
b.DoIt();
d.DoIt();
bd.DoIt();
b.DoItVirtual1();
d.DoItVirtual1();
bd.DoItVirtual1();
b.DoItVirtual2();
d.DoItVirtual2();
bd.DoItVirtual2();
}
}
输出:
Base: DoIt
Derived: DoIt
Base: DoIt
Base: DoItVirtual1
Derived: DoItVirtual1
Derived: DoItVirtual1
Base: DoItVirtual2
Derived: DoItVirtual2
Base: DoItVirtual2
new
修饰符产生的功能与要删除它的功能相同,但会抑制编译器关于无意中隐藏基类方法的警告
通过使用new,您声明您知道该成员
它修改隐藏从基类继承的成员
virtual
关键字与此处的new
修饰符无关。它只允许您覆盖派生类中的方法
此处的更多信息:在派生类中使用“new”关键字与不使用“new”具有相同的效果,无论是否存在“virtual”关键字
“虚拟”与“覆盖”成对工作
“new”仅在派生类上下文中起作用
如果它们不同,为什么在下面的示例中它们的行为相同
using System;
public class Base
{
public void DoIt()
{
Console.WriteLine ("Base: DoIt");
}
public virtual void DoItVirtual1()
{
Console.WriteLine ("Base: DoItVirtual1");
}
public virtual void DoItVirtual2()
{
Console.WriteLine ("Base: DoItVirtual2");
}
}
public class Derived : Base
{
public void DoIt()
{
Console.WriteLine ("Derived: DoIt");
}
public override void DoItVirtual1()
{
Console.WriteLine ("Derived: DoItVirtual1");
}
public new void DoItVirtual2()
{
Console.WriteLine ("Derived: DoItVirtual2");
}
}
class MainClass {
public static void Main (string[] args) {
Base b = new Base();
Derived d = new Derived();
Base bd = new Derived();
b.DoIt();
d.DoIt();
bd.DoIt();
b.DoItVirtual1();
d.DoItVirtual1();
bd.DoItVirtual1();
b.DoItVirtual2();
d.DoItVirtual2();
bd.DoItVirtual2();
}
}
查看输出中的差异:
Base: DoItVirtual1
Derived: DoItVirtual1
Derived: DoItVirtual1
Base: DoItVirtual2
Derived: DoItVirtual2
Base: DoItVirtual2
在重写的虚方法中,强制转换回基类的派生实例的行为类似于派生实例。这就是所谓的多态性。
在第二个示例中,在使用new关键字的情况下,运行时无法将强制转换实例与派生类连接。虚拟成员允许派生类替换实现,而新成员是将成员隐藏在具有相同名称的基类中的附加成员
class A
{
public virtual int X() => 1;
}
class B : A
{
public override int X() => 2;
}
class C : B
{
public new virtual int X() => 3;
}
class D : C
{
public sealed override int X() => 4;
}
试验
你是说
new
可以用同样的方式重新定义基本方法,而不管基本方法是否符合virtual
?否。new
和override
之间有重要区别<代码>覆盖启用多态性,而新建
不启用多态性。当使用覆盖
时,调用的方法始终是运行时类型。使用new
时,为了调用派生方法,静态类型(或编译器时间类型)必须是派生类。换句话说,如果您有BaseClass obj=new-DerivedClass()然后调用obj.DoItVirtual2()
,然后它将执行基类方法。如果您有DerivedClass obj=new-DerivedClass()代码>并执行相同的操作,它将运行DerivedClass方法。您不需要“重新定义”基方法。您只是故意在派生类中使用新定义“隐藏”基方法。对不起,我可能误解了您的问题<代码>新建
可以使用,无论虚拟
,是。但这与使用覆盖
不同。正如@Jacek所说,它隐藏了基本方法,而不是重新定义它。我们中的一些人想知道为什么语言设计者选择包含new
,因为大多数时候使用它意味着一种代码味道/一个有问题的架构/维护噩梦。此外,你永远不能调用操作(如基类中指定的)来自外部基类的虚拟成员。只有派生类才能调用base。$$$的可能重复项