Introduction
In this post, we will discuss the concept of Shadowing in OOP using C#, and we will see how it works, which will give you some idea of where we can use it, and hopefully, you will be able to decide when working practically in C# where it can be useful.
What is Shadowing?
Shadowing is a concept of the OOP (Object Oriented Programming) paradigm. Using Shadowing, we can provide a new implementation to the base class member without overriding it, which means that the original implementation of the base class member gets shadowed (hidden) with the new implementation of the base class member provided in the derived class.
Consider a scenario where you have an external assembly that you have added to your project. You have a class in that assembly, and it has a method that is not defined as virtual, and you want to override that method (define your own implementation for that method) in the derived class. What would you do?
This is the scenario where you can use the shadowing concept to override the method in the derived class.
The following are a few definitions of it.
According to MSDN
- Shadowing is the concept of using Polymorphism in Object Oriented Programming. When two programming elements share the same name, one of them can hide or shadow the other one. In such a situation, the shadowed element is not available for reference; instead, when your code uses the element name, the compiler resolves it to the shadowing element.
- Shadowing is actually hiding the overridden method implementation in the derived class and calling the parent call implementation using the derived class object.
Difference between Overriding and Shadowing
There is a major difference in shadowing and overriding which is normally when we override a virtual method in the derived class and create an instance of the derived class, and then if we hold reference to the derived class object as a base class object, and call that member, it always calls derived class implementation which is supposed to happen. In shadowing, the case is different. If, for the same virtual member, we shadow it in the derived class using a new keyword and we call the implementation as above, it will call base class implementation when we have reference to an object of type base class. And if we have a reference to the same object of derived type, it will call derived type implementation, so base class and derived class implementation are hidden from each other. The method of choosing which implementation to call depends upon if we are calling the member using the reference of base type or derived type.
Example. Suppose I have a base class BaseLogger which has two virtual methods (which means they can be overridden in a subclass) defined as.
public abstract class BaseLogger
{
public virtual void Log(string message)
{
Console.WriteLine("Base: " + message);
}
public virtual void LogCompleted()
{
Console.WriteLine("Completed");
}
}
Now I create a class Logger that inherits from the BaseLogger class. The logger class looks like this.
public class Logger : BaseLogger
{
public override void Log(string message)
{
Console.WriteLine(message);
}
public new void LogCompleted()
{
Console.WriteLine("Finished");
}
}
Now I want my Console to print the following lines.
- Log started
- Base: Log Continuing
- Completed
What should be written in the main program to get the above output? Here is the code we will need to write.
public class Program
{
public static void Main()
{
BaseLogger logger = new Logger();
logger.Log("Log started!");
logger.Log("Base: Log Continuing");
logger.LogCompleted();
}
}
The first call to the Log method is OK, it is called the Derived Logger class Log method, and it should be because we have overridden it in the Logger class.
The second call is also the same.
Now note the third call. It is called the base class LogCompleted() method, not the derived class. It is because we have defined the derived class method with a new keyword which hides the derived class method when we are calling it with the object of type BaseLogger, which is our base class.
If we want to call the derived class LogCompleted() method, our object reference should be of type Logger, not BaseLogger, while in method overriding, this is not the case.
In method overriding, if we cast the object of the derived class to a base class and call the method, it will call the overridden implementation of the derived class.
Read more articles on C#.