Calling Virtual and Non-virtual Methods for C#
Learn how you can call a method on a base class and cause its derived class's method to be executed with the magic of CLR.
Nov 7, 2019 • 8 Minute Read
Introduction
The third pillar of object-oriented programming is commonly called polymorphism, a Greek word that is translated as "many shaped."
Polymorphism has two distinct aspects. At runtime, objects of a derived class can be treated as objects of a base class in specific places such as method parameters and collections or arrays. When this occurs, the declared type of the object is no longer identical to its run-time type. The other aspect is that base classes can define and implement virtual methods, and the derived classes are able to override them. The derived classes inject their own implementation and definition of the virtual method. This means that in your application, you are able to call a method on a base class and cause its derived class's method to be executed. This is done behind the scenes with the magic of CLR, which looks up the run-time type of the object and invokes the overridden version of the virtual method.
Virtual and Non-virtual Methods
Virtual and non-virtual methods support the polymorphistic features of C#, combining the virtual keyword with the override. With the combination of the virtual on the base class method and the override on the method in the derived class, both methods are said to be virtual methods.
In simple terms, this method can be redefined in derived classes.
The implementation is present in both the base and derived class, and most of the time in derived classes, extra functionality is added. When we declare a method as virtual in a base class, then we have the possibility to define it in the base class, and optionally the override becomes available in derived classes. When the method is declared as virtual in a base class, and the same definition exists in a derived class, there is no need for override, but a different definition will only work if the method is overridden in the derived class.
Two important rules:
- By default, methods are non-virtual, and they cannot be overridden.
- Virtual modifiers cannot be used with static, abstract, private, and override modifiers.
Let's demonstrate this with a code example.
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();
}
}
}
The output of the code looks something like this:
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!
But what is happening behind the scenes? Let's dissect the example.
We have two classes. One is Person and the other is Men. The Person is the base class with two methods, Age() and Introduction(). The latter is a virtual method, the former is a non-virtual method. The Introduction() method is overridden in the derived class.
In our Main function, we instantiate the Men class with the instance Dani and then assign the instance to the Person base classes new instance. When the virtual and non-virtual methods are invoked in both of the class instances, the subclass override is invoked in both cases, showcasing the polymorphism and the internal working of the virtual keyword.
How the Override Works
Here's another great example to demonstrate how this override works.
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();
}
}
}
The output of the execution looks like this:
Server :: The device with name: CUSTOMERDC1 is located in datacenter: DCA
ConfigurationItem :: The device with name: CUSTOMERSW1 is located in datacenter: Default Location
Let's dissect this example and see what is happening behind the scenes.
This time we have three classes: ConfigurationItem, Server, and Switch. The first one is the base class. Both Server and Switch are derived from the base class. Base class ConfigurationItem has a virtual method called DeviceInfo(). This method is overridden in the Server class but not in the Switch class. When the virtual methods are overridden in a derived class, that derived class uses an instance, then invokes a derived class overridden method. When the virtual method is not overridden in a derived class and uses that derived class instance, it invokes the base class's virtual method.
Conclusion
In this written guide we have explored the functions that allow you to create polymorphic code in C# using virtual and non-virtual methods. This is a pretty neat tool in a developer's toolset. It allows you to create more robust applications that are easy to extend and stand the test of time. We have walked through two distinct examples that give you an idea as to how you can implement this feature and incorporate it into your application.
I hope this has been informative and worth your time. Thanks for reading, and give it a thumbs up if you liked it.