In this article, we are going to describe the types of inheritance in C# and their use in various scenarios.
Let’s dive in.
What is Inheritance in C#?
The inheritance is one of the main object-oriented programming paradigms, and it permits the reuse of the same code in more than one class. This way, instead of re-writing the same code in several places, we use inheritance to define a class based on another one already defined. We use a base class to create derived classes.
In this article, we will focus on different inheritance types. There are 3 types of inheritance in C#:
- Single Inheritance
- Multilevel Inheritance
- Multiple Inheritance (with interfaces)
To get to the heart of the matter let’s define a base class:
public class MobileDevice { public string OperatingSystem { get; set; } = null!; public double Inches { get; set; } public bool IsConnected { get; set; } public virtual bool DeviceCanMakePhoneCall() { return false; } }
The MobileDevice
is a class with three properties: OperatingSystem
, Inches
and IsConnected
. It implements the method DeviceCanMakePhoneCall()
of returning false
. The virtual
keyword forces the override of this method in its derived classes.
Now, let’s dive into each type of inheritance in C# in more detail.
Single Inheritance
The simplest type of inheritance is the single inheritance.Â
Let’s introduce a new Smartphone
class:
public class Smartphone : MobileDevice { public List<string> InstalledApps { get; private set; } public Smartphone() { InstalledApps = new List<string>(); } protected Smartphone(string operatingSystem) { OperatingSystem = operatingSystem; InstalledApps = new List<string>(); } public override bool DeviceCanMakePhoneCall() { return true; } public virtual void GetDescription() { Console.WriteLine($"This smartphone is {Inches} inches big and its operating system is {OperatingSystem}"); } public void ShowInstalledApps() { Console.WriteLine($"There are {InstalledApps.Count} app installed"); } }
Smartphone
inherits from the base class MobileDevice
and it overrides the method DeviceCanMakePhoneCall()
, returning true
.
We can define an instance of Smartphone
class now:
var smartphone = new Smartphone() { Inches = 5.5, OperatingSystem = "iOS" };
We set Inches
and OperatingSystem
properties inherited from MobileDevice
. The GetDescription()
method has the virtual
modifier which means all derived classes must override it. Moreover, we’ve added ShowInstalledApp()
, that prints the number of installed apps. This method has just a public
modifier. This means that any class inheriting from Smartphone
will have the same implementation of this method.
If we call the smartphone.GetDescription()
and smartphone.ShowInstalledApps()
methods, we’ll get the values we’ve set for our Smartphone
instance:
This smartphone is 5,5 inches big and its operating system is iOS There are 0 app installed
Finally, the property InstalledApps
represents a list of apps downloaded on the device. In fact, the derived class can have its own properties other than the ones it has inherited from the base class:
Multilevel Inheritance
The multilevel inheritance permits deriving a class from another one already derived from a base class. For example, let’s declare the AndroidSmartphone
:
public class AndroidSmartphone : Smartphone { public AndroidSmartphone() : base(operatingSystem: "Android") { } public override void GetDescription() { Console.WriteLine($"This Android smarphone is {Inches} inches big, and {InstalledApps.Count} apps downloaded from Google Store"); } public void DownloadAppFromStore(string app) { InstalledApps.Add(app); Console.WriteLine($"I downloaded {app} from Google Store"); } }
The AndroidSmartphone
class inherits the properties from the Smartphone
class but the value of the OperatingSystem
property is always equal to “Android”. In fact, in this case, we fix it in the constructor, so when we define a new instance of AndroidSmartphone
, we don’t need to set it manually. Â
AndroidSmartphone
overrides the GetDescription()
method that was virtual
in the Smartphone
class. As with the properties, the derived classes can have unique methods like DownloadAppFromStore(string app)
.
To continue, let’s create an AndroidSmartphone
instance and invoke the methods:
var androidSmartphone = new AndroidSmartphone() { Inches = 4, }; androidSmartphone.GetDescription(); androidSmartphone.DownloadAppFromStore("WhatsApp"); androidSmartphone.ShowInstalledApps(); Console.WriteLine(androidSmartphone.OperatingSystem); Console.WriteLine(androidSmartphone is MobileDevice);
Since we are using multilevel inheritance, the androidSmartphone is MobileDevice
statement prints out true
:
This Android smarphone is 4 inches big, and 0 apps downloaded from Google Store I downloaded WhatsApp from Google Store There are 1 app installed Android True
Finally, the output of GetDescription()
is different from the one implemented in Smartphone
class, since we override it:
Â
Multiple Inheritance
C# doesn’t have a concept of multiple inheritance exactly, which permits multiple classes to inherit from a single base class.Â
To demonstrate how we can go around this problem, we’re going to create a ConvertibleNotebook
class first:
public class ConvertibleNotebook : MobileDevice { public int UsbPortNumbers { get; set; } public override bool DeviceCanMakePhoneCall() { if (IsConnected) { return true; } return false; } public void WriteWithKeyboard(string message) { Console.WriteLine(message); } }
A ConvertibleNotebook
inherits from MobileDevice
all the properties and it overrides the DeviceCanMakePhoneCall()
. Moreover, it has UsbPortNumber
property, and the WriteWithKeyboard(string message)
method that prints on the console a message passed as a parameter. Â
Basically, Smartphone
and ConvertibleNotebook
classes have the common methods and properties defined by MobileDevice
class, but they also have their own properties and methods that define them more specifically.
Let’s create an instance of ConvertibleNotebook
class:
var convertibleNotebook = new ConvertibleNotebook() { Inches = 11.6, OperatingSystem = "Windows 11", UsbPortNumbers = 3 }; convertibleNotebook.DeviceCanMakePhoneCall(); convertibleNotebook.WriteWithKeyboard("I can write with keyboard");
A ConvertibleNotebook
inherits from MobileDevice
the properties Inches
and OperatingSystem
and it also has the UsbPortNumbers
property:
C# doesn’t permit the inheritance from more than one base class. This is mainly because this would add too much complexity, without too much benefit. (see the diamond problem for more information)
Let’s consider ConvertibleNotebook
. Since it already inherits the MobileDevice
class, it can not inherit another class. Inheriting from another class results in a compiler error “Class {DerivedClassName} cannot have multiple base classes ‘{BaseClass1Name}’ and ‘{BaseClass2Name}’.
We can overcome this problem using an interface:
public interface ILaptop { public int UsbPortNumbers { get; set; } public void WriteWithKeyboard(string message); }
Now the ConvertibleNotebook
class can inherit both from the MobileDevice
class, and the ILaptop
interface:
public class ConvertibleNotebook : MobileDevice, ILaptop { public int UsbPortNumbers { get; set; } public override bool DeviceCanMakePhoneCall() { if (IsConnected) { return true; } return false; } public void WriteWithKeyboard(string message) { Console.WriteLine(message); } }
This way, ConvertibleNotebook
implements ILaptop
interface providing an implementation of WriteWithKeyboard(string message)
, but it also inherits from MobileDevice
class overriding DeviceCanMakeCall()
.
How to Prevent Inheritance in C#
We know that not all methods (or properties) of a class should be visible in the derived classes. To do so, for the overridden methods, like GetDescription()
in the AndroidSmartphone
class, we need to use the sealed
keyword:
public override sealed void GetDescription() { Console.WriteLine($"This Android smarphone is {Inches} inches big, and {InstalledApps.Count} apps downloaded from Google Store"); }
This way, any other derived class will not be able to inherit this method. When we deal with property or with a not-overridden method, instead, we need to use the private
modifier. For example, we can modify in the Smartphone
class:
private void ShowInstalledApps() { Console.WriteLine($"There are {InstalledApps.Count} app installed"); }
In this case, if we try to invoke it on AndroidSmarphone
instance, we will have a compilation error. In factShowInstalledApps()
is private
in Smartphone
class and not visible in AndroidSmartphone
:
androidSmartphone.ShowInstalledApps(); //Error CS0122 'Smartphone.ShowInstalledApps()' is inaccessible due to its protection level
We can also make the entire class sealed as well.
Conclusions
In this article, we covered the different types of inheritance in C# and we’ve shown how we can use it or prevent it in our applications.
Multiple generations of single inheritance doesn’t make multiple inheritance.
Multiple inheritance is when one single class has two or more parents.
Like, let’s say you have your
MobileDevice
, and you have aCamera
, and you put those two together to make aMobileDeviceWithCamera
by inheriting from both:public class MobileDeviceWithCamera: MobileDevice, Camera { }
. This is something not supported by c# – which is perfectly fine by me. Multiple inheritance comes with way too much potential trouble for my taste…