THE POLYMORPHISM IN C#
Polymorphism in c sharp is the third pillar of Object Oriented programming, literally it means “having many forms” it means in practice that starting from a base class that has a certain behavior, we can redefine this behavior in its derived classes. Let’s see the theory behind polymorphism with some images.
POLYMORPHISM IN C SHARP THE OVERRIDE
METHODS VIRTUAL AND OVERRIDE
Let’s move from theory to practice by looking at what are the mechanisms that the C# language makes available to us to implement polymorphism in C Sharp.
using System; namespace Polimorfismo { class Program { static void Main(string[] args) { Insetto i = new Insetto(); i.MyMethod(); } public class Animale { public void MyMethod() { Console.WriteLine("Sto eseguendo MyMethod() della Superclasse"); } } public class Insetto:Animale { public void MyMethod() { Console.WriteLine("Sto eseguendo MyMethod() della Sottoclasse"); } } } }
POLYMORPHISM IN C SHARP COMPILER’S WARNING
If we try to run this code the compiler will give us a warning (MyMethod() hides the inherited member ‘Program.Animale.MyMethod()‘. If this behavior is intentional, use the new keyword) as it is able to understand that we are overriding a method of the base class but have not explicitly declared it in the code. If we create an instance of the Insetto class, the code of the method of that class will still be executed.
THE KEYWORDS VIRTUAL AND OVERRIDE
To remove this warning you need to use the virtual keyword in the base class which tells the compiler that we are voluntarily redefining the superclass MyMethod() method in a subclass. Using the keyword virtual we are indicating to the compiler that it is possible to override the method. In derived classes, the override keyword must be specified to remove the compiler signal and manage the code correctly.
Let’s see how to correctly manage the override (if necessary) of a method of the Superclass in the derived class or classes. If in the derived class we want to call the Superclass method first and then add additional code we have to do it using the base keyword followed by the dot and MyMethod();
using System; namespace Polimorfismo { class Program { static void Main(string[] args) { Insetto i = new Insetto(); i.MyMethod(); } public class Animale { public virtual void MyMethod() { Console.WriteLine("I am running MyMethod() of the Superclass."); } } public class Insetto:Animale { public override void MyMethod() { Console.WriteLine("I am running MyMethod() of the Subclass."); } } } }
THE ABSTRACT CLASSES
In c sharp polymorphism, if we declare a method with the abstract keyword this method must simply be a placeholder with no implementation that indicates to the derived classes that they must necessarily implement this method. We have seen that if a method is declared abstract then the whole class must be abstract. Derived classes must continue to use the override keyword. Abstract classes can contain static class methods that have their own implementation, so they can be partially implemented.
using System; namespace Polimorfismo { class Program { static void Main(string[] args) { Animale i = new Insetto(); i.MyMethod(); Animale.MyMethod2(); } } public abstract class Animale { public abstract void MyMethod(); public static void MyMethod2() { Console.WriteLine("I am running the static method MyMethod2() of the Superclass."); } } public class Insetto:Animale { public override void MyMethod() { Console.WriteLine("I am running MyMethod() of the Subclass."); } } }
Let’s look at some important mechanisms of polymorphism with some example code.
using System; namespace Polimorfismo { class Program { static void Main(string[] args) { Animale a = new Insetto(); Animale b = new Mammifero(); a.MyMethod();//THE METHOD OF THE INSETTO DERIVATED CLASS IS PERFORMED b.MyMethod();//THE METHOD OF THE MAMMIFERO DERIVATED CLASS IS PERFORMED } } public class Animale { public virtual void MyMethod() { Console.WriteLine("Sto eseguendo MyMethod() della Superclasse."); } } public class Insetto:Animale { public override void MyMethod() { Console.WriteLine("Sto eseguendo MyMethod() della Sottoclasse Insetto."); } } public class Mammifero:Animale { public override void MyMethod() { Console.WriteLine("Sto eseguendo MyMethod() della Sottoclasse Mammifero."); } } }
We have defined two object variables relating to the Animale class a and b we have initialized them with the Insetto and Mammifero class, a and b are in fact two objects belonging to the Animale class if we try to execute MyMethod() on these two object variables the code that is executed is the relative one to subclasses and not to the base class.
IN SUMMARY
Polymorphism represents the principle according to which different derived classes can implement the same behavior defined in the base class in a different way. Since in .NET 5 every class derives directly or indirectly from System.Object, each object exhibits a number of common behaviors, some of which can be specialized by exploiting polymorphism. These behaviors include the ToString, GetHashCode, and Equals functions, the default implementation of which is included in the System.Object base class.
UNDERSTANDING THE HIERARCHY OF HERARCHY USED IN THE CODE
Taking up the example proposed in the case of heredity, we consider two behaviors common to all animals: Respira and Mangia. In the animal world, these behaviors are implemented in specific ways depending on the species: a carnivore eats differently than a herbivore, a fish breathes differently than a bird. Based on these considerations, the Mangia and Respira behaviors, defined in the different classes derived from Animal, can be implemented in a specific and completely independent way from the other implementations (and, in particular, from that of the Animale base class).
EXERCISE
We redefine the Property Denominazione present in the Persona base class in the Utente derived class by adding the ID Utente. We also redefine the ToString () method present in the parent class of the inheritance chain of C# objects, i.e. the Object class.
using System; namespace EsercitazionePolimorfismo { internal class Program { private static void Main(string[] args) { Utente utente1 = new(){Id = "1234560",Nome = "Mario",Cognome = "Rossi",NumeroConto = "4356789"}; utente1.Saldo = 13000m; Utente utente2 = new(){Id="12345678", Nome = "Mario",Cognome = "Verdi",NumeroConto = "435679879"}; utente2.Saldo = 30000m; utente1.SaldoCorrente(); utente2.SaldoCorrente(); var b1 = new Banca("1234567890", "UBI Banca"); var b2 = new Banca("1234576543", "UBI Banca"); b1.Preleva(3000m,utente1); b2.Preleva(10000m,utente2); utente1.SaldoCorrente(); utente2.SaldoCorrente(); Console.WriteLine(utente2.Denominazione); Console.WriteLine(utente2.ToString()); //VIENE RICHIAMATO IL METODO RIDEFINITO NELLA CLASSE UTENTE } internal class Persona { public string Nome { get; set; } public string Cognome { get; set; } public virtual string Denominazione => "Utente " + Nome + " " + Cognome; } internal class Utente : Persona { private decimal saldo; public string Id { get; set; } public decimal Saldo { get => saldo; set { if (value < 0) Console.WriteLine($"Impossibile impostare il saldo. Valore passato: {value}"); else saldo = value; } } public string NumeroConto { get; set; } public override string Denominazione => "Utente " + Id + " " + Nome + " " + Cognome; internal void SaldoCorrente() { Console.WriteLine($"Utente {Nome + " " + Cognome} saldo corrente: {Saldo}"); } //ToString() è un metodo predefinito nella classe object. Tutti i tipi in C Sharp //Ereditano da questa classe che è la capostitipe di tutta la gerarchia di ereditarietà //degli oggetti C# public override string ToString() { return "Utente: " + Nome + " " + Cognome + " " + NumeroConto; } } internal class Banca { public Banca(string id, string denominazione, string abi, string cab) { Id = id; Denominazione = denominazione; Abi = abi; Cab = cab; } public Banca(string id, string denominazione) : this(id, denominazione, "06098", "14400") { } public string Id { get; set; } public string Denominazione { get; set; } public string Abi { get; set; } public string Cab { get; set; } public Utente Utente { get; set; } internal void Preleva(decimal importo, Utente utente) { this.Utente = utente; var saldo = Utente.Saldo; if (importo > saldo) { Console.WriteLine($"Operazione di prelievo non ammessa, importo richiesto {importo}"); return; } if (importo < 0) { Console.WriteLine($"Importo prelevato non valido: {importo}"); return; } Utente.Saldo -= importo; this.Utente = null; } internal void Accredito(decimal importo, Utente utente) { this.Utente = utente; if (importo < 0) { Console.WriteLine($"Importo accreditato non valido: {importo}"); return; } Utente.Saldo += importo; this.Utente = null; } } } }
IN-DEPTH STUDY OF POLYMORPHISM
Polymorphism in C# is a fundamental concept of object-oriented programming that allows objects to be treated as instances of their base class rather than their derived class. This means that a single interface can be used for different types of objects. In C#, polymorphism is achieved primarily through inheritance and the use of interfaces.
Types of Polymorphism in C#
1. Static Polymorphism (or Compile-Time Polymorphism):
– Method Overloading: Allows multiple methods with the same name but different signatures (different parameters).
– Operator Overloading: Allows defining or redefining the behavior of operators for user-defined types.
2. Dynamic Polymorphism (or Run-Time Polymorphism):
– Methods Override: Allows a derived class to provide a specific implementation of a method already defined in the base class. This is achieved by using the keywords virtual in the base class and override in the derived class.
– Interfaces: They define a contract that classes must implement. Classes that implement the interface can be treated uniformly.
Example of Dynamic Polymorphism with Method Overrides.
using System;
class Animale
{
public virtual void FaiSuono()
{
Console.WriteLine(“L’animale fa un suono.“);
}
}
class Cane : Animale
{
public override void FaiSuono()
{
Console.WriteLine(“Il cane abbaia.“);
}
}
class Gatto : Animale
{
public override void FaiSuono()
{
Console.WriteLine(“Il gatto miagola.“);
}
}
class Programma
{
static void Main(string[] args)
{
Animale mioAnimale = new Animale();
Animale mioCane = new Cane();
Animale mioGatto = new Gatto();
mioAnimale.FaiSuono(); // Output: L’animale fa un suono.
mioCane.FaiSuono(); // Output: Il cane abbaia.
mioGatto.FaiSuono(); // Output: Il gatto miagola.
}
}
In this example, the class Animal has a MakeSound method that is defined as virtual. The classes Dog and Cat inherit from Animal and override the MakeSound method using the override keyword. In the Main method, objects of type Dog and Cat are treated as objects of type Animal, but they call their respective implementations of the MakeSound method.
Polymorphism thus allows code to be written that is more flexible and reusable, facilitating software maintenance and extensibility.
Leave A Comment