BASIC CLASSES AND DERIVED CLASSES

Inheritance in c sharp is the second pillar of Object Oriented programming. Let us try to clarify the mechanism with a figure.

Inheritance

In C#, classes are the data structures that allow us to manage superclasses and subclasses, and therefore to implement the inheritance mechanism. Only they support inheritance, struct and enum that we have already seen do not implement this mechanism. Let’s see programmatically how an inheritance hierarchy is defined:

EXAMPLE OF INHERITANCE CHAIN

using System;
namespace Ereditarieta
{
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
    public class Animale
    {
        public void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
       
    }
    public class Insetto : Animale
    {
        
    }
    public class Uomo : Mammifero
    {
        
    }
}

C sharpAs you can see, I have defined a base class or superclass Animale with the public method Respira() as breathing is a feature common to all animals. To define subclasses or derived classes of Animale we declare a class normally as we are used to, add a colon and the name of the superclass. Obviously you can derive any number of subclasses from the base class, for example I have defined a Mammifero subclass and an Insetto subclass. The Mammifero class represents the superclass for the derived class Uomo which derives directly from Mammiferoand indirectly from Animale as man is also an animal species. The derived class Uomo inherits the Respira() method from the Animale class.

THE INHERITANCE IN C SHARP

As mentioned, inheritance is a mechanism that C# makes available to us, let’s try to explain this mechanism with a practical example.

using System;

namespace Ereditarieta
{
    class Program
    {
        static void Main(string[] args)
        {
            Mammifero m = new Mammifero();
            m.myInt=10;
            m.myString="Ereditarietà in C#";
            m.Respira();
            m.MyProperty="Pippo";
        }
    }
    public class Animale
    {
        public int myInt;
        public string MyProperty {get;set;}
        public void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
        public string myString;
        
    }
}

As you can see I have declared an integer myInt, the Respira() method and the MyProperty property in the base class or superclass. By creating an instance of the mammifero derived class, the attributes, methods and properties are automatically inherited from the base class. Any constructors are not inherited. However, there is a problem in this code, namely that it has declared the members of the superclass public. To solve this problem, C# provides us with a new access modifier that is protected which extends the visibility of the members of the superclass only to derived classes.

using System;

namespace Ereditarieta
{
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
    public class Animale
    {
        protected int myInt;
        protected string MyProperty {get;set;}
        protected void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
        protected string myString;
        
    }
}

INHERITANCE IN C SHARP LE KEYWORD IS E AS

Sometimes it is necessary to access only the members of the superclass, we can do this using the following syntax:

Animale a = new Mammifero();

The variable a is an object of the Animale class but its reference points to the derived class Mammifero.

using System;

namespace Ereditarieta
{
    public class Program
    {
        public static void Main(string[] args)
        {

             
             Animale a = new Mammifero(); // a is an object of the Animale superclass, 
                                          // but its reference points to the subclass 
                                          // Mammifero.
             a.myInt=10;
             a.MyProperty="pippo";
             a.Respira();
             if(a is Mammifero)    /*To bring the object back to the reference point, 
                                     that is to the Mammifero Class, the operators is and as can be used. is is a Boolean 
                                     operator that returns true if a is a mammifero instance. In this case the object 
                                     is accessed with a normal casting.*/
             {
               Mammifero m = (Mammifero)a;
               Mammifero m1 = a as Mammifero;/*You can also use the as keyword in
                                               which case the code is cleaner and more readable*/
               m.myInt=20;
               m.MyProperty="pluto";
               m.myString="Mario";
               m.Respira();
             }
             
            
        }
    }
    public class Animale
    {
        public int myInt;
        public string MyProperty {get;set;}
        public void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
        public string myString;
        
    }
}

INHERITANCE AND CONSTRUCTORS

By defining a constructor in the derived class and leaving the default constructor in the base class, creating an instance in the derived class will happen without problems as the compiler behind the scenes also creates an instance of the superclass using the default constructor.

using System;

namespace Ereditarieta
{
    public class Program
    {
        public static void Main(string[] args)
        {
           Mammifero m = new Mammifero("Pippo");   
        }
    }
    public class Animale
    {
        public int myInt;
        public string MyProperty {get;set;}
        public void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
        private string myString;
        public Mammifero(string myString)
        {
              this.myString=myString;
        }
        
    }
}

When we introduce a constructor in the base class and therefore we no longer have a default constructor but a constructor created by us, trying to create an instance of the derived class the compilation will fail because the constructor method with a parameter has not been invoked and therefore the internal variable myInt was not initialized. This leads to a compiler error.

Error

Let’s see how this situation can be solved:

using System;

namespace Ereditarieta
{
    public class Program
    {
        public static void Main(string[] args)
        {
           Mammifero m = new Mammifero("Pippo",20);   
        }
    }
    public class Animale
    {
        private int myInt;
        public string MyProperty {get;set;}
        public Animale(int myInt)
        {
             this.myInt=myInt;
        }
        public void Respira()
        {
            Console.WriteLine("Respira");
        }
    }
    public class Mammifero : Animale
    {
        private string myString;
        public Mammifero(string myString, int myInt):base(myInt)
        {
              this.myString=myString;
        }
        
    }
}

As you can see, to correctly initialize the superclass, an additional parameter must be specified in the constructor of the derived class with which the constructor of the base class is invoked using the base keyword followed by the parameter and the instance of the superclass is correctly initialized. base (myInt) does nothing but invoke the constructor of the base class.

C SHARP INHERITANCLE EXERCISE

Let’s take the management of a current account as a starting point and introduce a new Persona class in which we move the Nome, Cognome and Denominazione properties from the Utente class to the new Persona class and then derive Utente from Persona. The program output should remain unchanged.

using System;
namespace EsercitazioneEreditarieta
{
    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(4000m,utente1);
            b2.Preleva(10000m,utente2);
            utente1.SaldoCorrente();
            utente2.SaldoCorrente();
        }
    }

    internal class Persona
    {
        public string Nome { get; set; }
        public string Cognome { get; set; }

        public 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; }

        internal void SaldoCorrente()
        {
            Console.WriteLine($"Utente {Nome + " " + Cognome} saldo corrente: {Saldo}");
        }
    }

    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;
            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;
            Utente = null;
        }
    }
}

IN-DEPTH STUDY OF INHERITANCE

Inheritance is one of the pillars of object-oriented programming (OOP). In C#, it allows new classes to be created that inherit members of existing classes. This promotes code reuse and facilitates maintenance. Here is an example of how inheritance works in C#: Basic example. Suppose we have a base class Animal and a derived class Dog:

// Classe base
public class Animale
{
       public string Nome { get; set; }

       public void Mangia()
       {
         Console.WriteLine($”{Nome} sta mangiando.“);
       }
}

// Classe derivata
public class Cane : Animale
{
       public void Abbaia()
       {
         Console.WriteLine($”{Nome} sta abbaiando.“);
       }
}

class Program
{
      static void Main(string[] args)
      {
          Cane mioCane = new Cane();
          mioCane.Nome = “Fido“;
          mioCane.Mangia(); // Fido sta mangiando.
          mioCane.Abbia(); // Fido sta abbaiando.
      }
}

Access modifiers

– public: Accessible from anywhere in the program.

– private: Accessible only within the class in which it is defined.

– protected: Accessible within the class in which it is defined and in derived classes.

– internal: Accessible only within the same assembly.

Method overrides.

Derived classes can override methods of base classes using the override keyword.

public class Animale
{
        public string Nome { get; set; }

        public virtual void Verso()
        {
          Console.WriteLine($”{Nome} fa un verso.“);
        }
}

public class Cane : Animale
{
        public override void Verso()
        {
          Console.WriteLine($”{Nome} abbaia.“);
        }
}

class Program
{
     static void Main(string[] args)
     {
       Cane mioCane = new Cane();
       mioCane.Nome = “Fido“;
       mioCane.Verso(); // Fido abbaia.
    }
}

Basic keyword

The base keyword provides access to members of the base class from the derived class.

public class Animale
{
           public string Nome { get; set; }

           public virtual void Verso()
           {
               Console.WriteLine($”{Nome} fa un verso.“);
           }
}

public class Cane : Animale
{
          public override void Verso()
          {
               base.Verso();
               Console.WriteLine($”{Nome} abbaia.“);
          }
}

class Program
{
       static void Main(string[] args)
       {
           Cane mioCane = new Cane();
           mioCane.Nome = “Fido“;
           mioCane.Verso(); // Fido fa un verso.
                            // Fido abbaia.
       }
}

Abstract classes and abstract methods

An abstract class cannot be instantiated directly and can contain abstract methods that must be implemented in derived classes.

public abstract class Animale
{
        public string Nome { get; set; }

        public abstract void Verso();
}

public class Cane : Animale

{
     public override void Verso()
     {
          Console.WriteLine($”{Nome} abbaia.“);
     }
}

class Program
{
       static void Main(string[] args)
       {
            Cane mioCane = new Cane();
            mioCane.Nome = “Fido“;
            mioCane.Verso(); // Fido abbaia.
       }
}

LINKS TO PREVIOUS POST

LINK TO GITHUB CODE