调用 C# 的虚拟方法和非虚拟方法
介绍
面向对象编程的第三个支柱通常称为多态性,这是一个希腊词,翻译为“多种形状”。
多态性有两个不同的方面。在运行时,派生类的对象可以在特定位置(例如方法参数和集合或数组)被视为基类的对象。发生这种情况时,对象的声明类型不再与其运行时类型相同。另一个方面是基类可以定义和实现虚拟方法,而派生类可以重写它们。派生类注入自己的虚拟方法实现和定义。这意味着在您的应用程序中,您可以调用基类的方法并执行其派生类的方法。这是在幕后通过 CLR 的魔力完成的,CLR 会查找对象的运行时类型并调用虚拟方法的重写版本。
虚拟和非虚拟方法
虚拟方法和非虚拟方法支持 C# 的多态特性,将virtual关键字与override组合起来。通过将基类方法上的 virtual 与派生类方法上的 override 组合起来,这两种方法都称为虚拟方法。
简单来说,这个方法可以在派生类中重新定义。
实现存在于基类和派生类中,并且大多数情况下,在派生类中都会添加额外的功能。当我们在基类中将方法声明为虚拟方法时,我们就有可能在基类中定义它,并且可以选择在派生类中重写它。当在基类中将方法声明为虚拟方法,并且派生类中存在相同的定义时,就不需要重写,但只有在派生类中重写该方法时,不同的定义才会起作用。
两个重要规则:
- 默认情况下,方法是非虚拟的,并且不能被覆盖。
- Virtual 修饰符不能与 static、abstract、private 和 override 修饰符一起使用。
让我们通过代码示例来证明这一点。
using System;
namespace virtnonvirt
{
public class Person
{
public string _name;
public int _age;
public string _sex;
public Person(string name, int age, string sex)
{
this._age = age;
this._sex = sex;
this._name = name;
}
public void Age() {
Console.WriteLine($"Person :: Hi, I am {this._age} years old!");
}
public virtual void Introduction()
{
Console.WriteLine($"Person :: Hi, my name is {this._name}, I am {this._age} years old and I am a {this._sex}");
}
}
public class Men : Person
{
public Men(string name, int age) : base(name, age, "male")
{
}
public void Age()
{
Console.WriteLine($"Men :: Hi, I am {this._age} years old!");
}
public override void Introduction()
{
Console.WriteLine($"Men :: Hi, my name is {this._name}, I am {this._age} years old and I am a {this._sex}");
}
}
class Program
{
static void Main(string[] args)
{
Men Dani = new Men("Szabó Dániel Ernő", 28);
Person Alien = Dani;
Dani.Introduction();
Alien.Introduction();
Dani.Age();
Alien.Age();
Console.ReadKey();
}
}
}
代码的输出如下所示:
Men :: Hi, my name is Szabó Dániel Erno, I am 28 years old and I am a male
Men :: Hi, my name is Szabó Dániel Erno, I am 28 years old and I am a male
Men :: Hi, I am 28 years old!
Person :: Hi, I am 28 years old!
但幕后到底发生了什么?让我们分析一下这个例子。
我们有两个类。一个是Person,另一个是Men。Person是基类,有两个方法Age()和Introduction()。后者是虚拟方法,前者是非虚拟方法。在派生类中重写了Introduction()方法。
在Main函数中,我们使用Dani实例来实例化Men类,然后将该实例分配给Person基类的新实例。当在两个类实例中调用虚拟和非虚拟方法时,两种情况下都会调用子类覆盖,从而展示虚拟关键字的多态性和内部工作原理。
覆盖如何工作
这是另一个很好的例子,演示了此覆盖如何工作。
using System;
namespace virtnonvirt
{
public class ConfigurationItem {
public string _location;
public string _name;
public ConfigurationItem(string name, string location)
{
this._name = name;
this._location = location;
}
public ConfigurationItem(string name)
{
this._name = name;
this._location = "Default Location";
}
public virtual void DeviceInfo()
{
Console.WriteLine($"ConfigurationItem :: The device with name: {this._name} is located in datacenter: {this._location}");
}
}
public class Server : ConfigurationItem
{
public Server(string name, string location) : base(name, "DCA")
{
}
public override void DeviceInfo()
{
Console.WriteLine($"Server :: The device with name: {this._name} is located in datacenter: {this._location}");
}
}
public class Switch : ConfigurationItem
{
public Switch(string name) : base(name) { }
}
class Program
{
static void Main(string[] args)
{
Server DomainController = new Server("CUSTOMERDC1", "LasVegas");
DomainController.DeviceInfo();
Switch L2Switch = new Switch("CUSTOMERSW1");
L2Switch.DeviceInfo();
Console.ReadKey();
}
}
}
执行的输出如下:
Server :: The device with name: CUSTOMERDC1 is located in datacenter: DCA
ConfigurationItem :: The device with name: CUSTOMERSW1 is located in datacenter: Default Location
让我们剖析这个例子,看看幕后发生了什么。
这次我们有三个类:ConfigurationItem、Server和Switch。第一个是基类。Server和Switch都派生自基类。基类ConfigurationItem有一个名为DeviceInfo()的虚拟方法。此方法在Server类中被重写,但在Switch类中没有被重写。当在派生类中重写虚拟方法时,该派生类将使用一个实例,然后调用派生类重写的方法。当派生类中未重写虚拟方法并使用该派生类实例时,它将调用基类的虚拟方法。
结论
在本书面指南中,我们探索了允许您使用虚拟和非虚拟方法在 C# 中创建多态代码的函数。这是开发人员工具集中一个非常不错的工具。它允许您创建更强大的应用程序,这些应用程序易于扩展且经得起时间的考验。我们介绍了两个不同的示例,让您了解如何实现此功能并将其合并到您的应用程序中。
希望本文能为您带来有益信息,值得您花时间阅读。感谢您的阅读,如果您喜欢,请点赞。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~