理解C#中的隐藏(Shadowing)概念

面向对象编程(OOP)中,隐藏(Shadowing)是一个重要的概念,它允许在派生类中为基类成员提供新的实现,而不需要覆盖它。这意味着基类成员的原始实现被派生类中提供的新的实现所隐藏。

设想一个场景,在一个项目中添加了一个外部程序集,并且该程序集中有一个类,其中有一个方法没有被定义为虚拟的,但希望在派生类中覆盖这个方法(为这个方法定义自己的实现)。在这种情况下,可以使用隐藏的概念来在派生类中覆盖这个方法。

隐藏的定义

以下是隐藏的几个定义:

根据MSDN的定义,隐藏是面向对象编程多态性的一种概念。当两个编程元素共享相同的名称时,其中一个可以隐藏或覆盖另一个。在这种情况下,被隐藏的元素不可用,而是当代码使用元素名称时,编译器将其解析为隐藏的元素。

隐藏实际上是在派生类中隐藏覆盖的方法实现,并使用派生类对象调用父类实现。

隐藏与覆盖的区别

隐藏和覆盖之间有一个主要的区别。通常,当在派生类中覆盖一个虚拟方法,并创建派生类的实例,然后如果持有派生类对象的基类引用,并调用该成员,它总是调用派生类实现,这是应该发生的。但在隐藏的情况下,情况就不同了,如果在派生类中使用new关键字隐藏同一个虚拟成员,并且像上面那样调用实现,它将调用基类实现,当有基类类型的对象引用时,如果有相同对象的派生类型引用,它将调用派生类型实现,因此基类和派生类的实现彼此隐藏,调用哪个实现的方法取决于否使用基类或派生类的引用来调用成员。

假设有一个基类BaseLogger,它定义了两个虚拟方法(意味着它们可以在子类中被覆盖):

public abstract class BaseLogger { public virtual void Log(string message) { Console.WriteLine("Base: " + message); } public virtual void LogCompleted() { Console.WriteLine("Completed"); } }

现在,创建了一个类Logger,它继承自BaseLogger类。Logger类如下所示:

public class Logger : BaseLogger { public override void Log(string message) { Console.WriteLine(message); } public new void LogCompleted() { Console.WriteLine("Finished"); } }

现在,希望控制台打印以下行:

Log started! Base: Log Continuing Completed

应该在主程序中写什么代码来获得上述输出?这是需要编写的代码:

public class Program { public static void Main() { BaseLogger logger = new Logger(); logger.Log("Log started!"); logger.Log("Base: Log Continuing"); logger.LogCompleted(); } }

第一个对Log方法的调用是正确的,它调用了派生Logger类Log方法,应该这样做,因为在Logger类中覆盖了它。第二个调用也是一样的。

现在注意第三个调用,它调用了基类LogCompleted()方法,而不是派生类,这是因为使用new关键字定义了派生类方法,当使用BaseLogger类型的对象调用它时,它隐藏了派生类方法,如果没有使用new关键字,编译器会认为需要隐藏或覆盖,并且在编译时会显示警告,说:

use the new keyword if hiding was intended
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485