Take advantage of polymorphism to isolate interface from implementation and promote flexibility in your designs Polymorphism refers to the ability to present the same interface for different forms. Although the concept of polymorphism is the same in all programming languages that support it, its implementation differs from one language to another. The three types of polymorphism are overloading, parametric, and inclusion. Polymorphism helps to promote flexibility in designs by allowing the same method to have different implementations. In essence, you can leverage polymorphism to separate interface from implementation. It promotes code reuse and separation of concerns in your application. Overloading polymorphism is a type that exists in classes that are independent of each other — they are not related (inheritance, dependency, etc.) to each other in any way. As an example, you can have two distinct classes not related in any way with each other and having a method with the same name. Operator overloading is an example of this type of polymorphism. Parametric polymorphism, or template polymorphism, is a type where you have more than one method in your class with identical names but varying parameters, i.e., they all have the same method names, but they differ in the parameters. Inclusion polymorphism is also known as redefinition or method overriding. In this type of polymorphism, a sub class can redefine a method of the base class. This ability is also known as specialization. Parametric polymorphism This refers to the form of polymorphism where you have more than one method in your class that has the same name but they differ in their method signatures. A method signature comprises of the return type of the method, the type of the parameters to the method and the sequence of these parameters. Hence, a method that accepts an integer and a character as an argument differs in the signature from another method that accepts a character and an integer as arguments even though the return types of both these methods (having identical method names) are the same. The compiler determines the exact method to be called by comparing the method signatures of the overloaded methods. The following code listing illustrates how method overloading can be implemented. public enum Severity { Informational, Warning, Critical } public class Logger { public void Log(string message) { //Some code } public void Log(string message, Severity severity) { //Some code } } Refer to the code listing above. Note how the Log() method has been overloaded. This is an example of compile time polymorphism. Inclusion polymorphism Inclusion polymorphism, or method overriding, can be achieved in C# using virtual methods. In method overriding, you have methods having identical signatures present in both the base and the derived classes. You would typically want to use virtual methods to implement run-time polymorphism or late binding. Note that a virtual method is one that is declared as virtual in the base class and you can allow the subclasses of the type to override the virtual method(s). The following code snippet shows two classes — the base class named Logger that contains a virtual method called Log and a derived class named FileLogger that extends the Logger class and overrides the Log method of the base class. public class Logger { public virtual void Log(string message) { Console.WriteLine("Inside the Log method of the base class Logger"); } } public class FileLogger : Logger { public override void Log(string message) { Console.WriteLine("Inside the Log method of the FileLogger class"); } } This is an example of method overriding. Both the base and the derived classes have the same method with identical signatures. We use method overriding to implement run time polymorphism or late binding. The following code snippet shows how the Log method can be called using a reference of the base class. static void Main(string[] args) { Logger logger = new FileLogger(); logger.Log("Hello World!"); Console.ReadKey(); } When you execute the above code snippet, the Log method of the derived class, i.e., the Filelogger class would be invoked. If the Log method wasn’t declared as virtual in the base class, the base version of the Log method would have been called instead. Since this binding occurs late at run-time, this type of polymorphism is known as run-time polymorphism or late binding. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos