LE PROPERTY IN C#

C sharpLe property in C# sono il meccanismo che ci mette a disposizione il linguaggio per realizzare l’incapsulamento dei dati. Abbiamo visto nel post precedente come sia possibile incapsulare una certa variabile definita all’interno di una classe, rendendola privata, e implementando due metodi pubblici che consentono rispettivamente di accedere dall’esterno in lettura e scrittura alla variabile stessa. Riporto il codice:

using System;
namespace Property
{
    public class Persona
    {
        private string nome;
        public string GetNome()
        {
            return this.nome;
        }
        public void SetNome(string nome)
        {
            //qui ci vanno eventuali controlli prima di assegnare l'attributo nome.
            this.nome=nome;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
                     
        }
    }
}

Questo modo di rendere privati gli attributi o variabili di istanza consente di nascondere all’esterno la gestione dell’attributo, infatti definendo due metodi pubblici che in gergo vengono chiamati Getter e Setter la variabile prima di presentarla all’esterno può nei metodi appena citati scrivere codice supplementare come ad esempio la validazione. Siccome queste sono operazioni frequenti il C# ci viene incontro con le property che rappresentano il meccanismo per realizzare l’incapsulamento. Vediamo come si dichiara e implementa una property.

using System;
namespace Property
{
    public class Persona
    {
        private string nome;
        public string Nome
        {
            get{
                 return this.nome;
            }
            set{
                  this.nome=value;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
                     
        }
    }
}

Viene dichiarata una proprietà pubblica avente per convenzione lo stesso nome dell’attributo ma con l’iniziale maiuscola e aperto un blocco di codice in cui i metodi Getter e Setter sono sostituiti con le keyword get e set. Inoltre viene definita la parola chiave value che dietro le quinte accede al nuovo valore passato. Nei blocchi di codice get e set nulla ci vieta di scrivere codice supplementare.

PROPERTY IN C SHARP COME UTILIZZARLE

Dopo aver definito una property vediamo come essa viene usata dall’esterno. Ti riporto il codice

using System;
namespace Property
{
    public class Persona
    {
        private string nome;
        public string Nome
        {
            get{
                return this.nome;
            }
            set{
                this.nome=value;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Persona p = new Persona();
            p.Nome="Marco";/*--VIENE INVOCATO IL METODO SET DELLA PROPERTY
                             E ALLA KEYWORD VALUE VIENE PASSATO IL VALORE
                             "MARCO" NULLA CI VIETA DI ACCEDERE A VALUE E
                             FARE TUTTI I CONTROLLI O MODIFICARNE IL VALORE.*/
            Console.WriteLine(p.Nome);//VIENE INVOCATO IL GET DELLA PROPERTY.          
        }
    }
}

Come vedi prima si crea un’istanza della classe Persona poi si accede alla property Nome.

BACKING FIELD DI UNA PROPERTY IN C SHARP

Quando dichiariamo una property il backing field ossia la variabile privata private string nome non è obbligatorio dichiararla, inoltre le property hanno i modificatori di accesso, nell’esempio che ti ho fatto sopra la property è definita pubblica quindi get e set erediteranno tale modificatore, tuttavia possiamo cambiare il comportamento di default ad esempio implementando un set privato. Ciò significa che la proprietà sarà in sola lettura e quindi si può impostare solo all’interno della classe.

using System;
namespace Property
{
    public class Persona
    {
        private string nome;
        public string Nome
        {
            get{
                return this.nome;
            }
            private set{
                  this.nome=value;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
                  
        }
    }
}

AUTO IMPLEMENTED PROPERTY

Se non implementiamo codice nel get e nel set è possibile condensare ulteriormente una proprietà nel seguente modo:

using System;
namespace Property
{
    public class Persona
    {
        public string Nome {get;set;}
    }
    class Program
    {
        static void Main(string[] args)
        {
            Persona p = new Persona();
            p.Nome="Mario";
            string s = p.Nome;      
        }
    }
}

In tal caso sarà il compilatore a generare dietro le quinte il campo privato ossia il backing field e il resto del codice della property. È possibile specificare anche un valore di default nel seguente modo:

using System;
namespace Property
{
    public class Persona
    {
        public string Nome {get;set;}="Marco";
    }
    class Program
    {
        static void Main(string[] args)
        {
            Persona p = new Persona();
            p.Nome="Mario";
            string s = p.Nome;      
        }
    }
}

OBJECT INITIALIZER

È possible inizializzare le property in un colpo solo con questa sintassi:

using System;
namespace Property
{
    public class Persona
    {
        public string Nome {get;set;}
        public String Cognome {get;set;}
    }
    class Program
    {
        static void Main(string[] args)
        {
            Persona p = new() {Nome="Mario",Cognome="Verdi"};
        }
    }
}

RIPRENDIAMO IL CODICE DI ESEMPIO PRECEDENTE E MODIFICHIAMOLO USANDO LE PROPERTY

using System;
namespace EsercitazioneProperty
{
    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();
        }
    }

    internal class Utente
    {
        private decimal saldo;

        public string Id { get; set; }
        public string Nome { get; set; }
        public string Cognome { 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 string Denominazione => "Utente " + Nome + " " + Cognome;

        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)
        {
            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)
        {
            Utente = utente;
            if (importo < 0)
            {
                Console.WriteLine($"Importo accreditato non valido: {importo}");
                return;
            }

            Utente.Saldo += importo;
            Utente = null;
        }
    }
}

APPROFONDIMENTO

Le proprietà in C# sono un modo elegante per accedere ai campi privati di una classe. Permettono di controllare la lettura e la scrittura dei dati in modo sicuro e sono una parte fondamentale dell’incapsulamento nella programmazione orientata agli oggetti. Ecco una spiegazione semplice con un esempio:

Cos’è una proprietà?

Una proprietà in C# è un membro di una classe che fornisce un meccanismo flessibile per leggere, scrivere o calcolare il valore di un campo privato. Una proprietà può essere lettura-scrittura, sola lettura o sola scrittura.

Sintassi di base

Ecco un esempio di una classe con una proprietà:

public class Persona
{
              // Campo privato
              private string nome;

              //Proprietà pubblica
              public string Nome
              {
                   get
                    {
                      return nome;
                    }
                   set
                    {
                      nome = value;
                    }
              }
}

Spiegazione dell’esempio

1. Campo privato: private string nome;

• Questo è un campo privato della classe Persona. È privato, quindi può essere accessibile solo all’interno della classe stessa.

2. Proprietà pubblica: public string Nome { get; set; }

get è un accessore che restituisce il valore del campo privato nome.

set è un modificatore che imposta il valore del campo privato nome.

• Questa proprietà permette di leggere e scrivere il valore di nome dall’esterno della classe, ma tramite i metodi get e set.

Utilizzo della proprietà

Ecco come puoi usare questa proprietà:

public class Programma
{
     public static void Main()
{
Persona persona = new Persona();

          // Impostare il valore tramite la proprietà
          persona.Nome = “Mario Rossi“;

         // Ottenere il valore tramite la proprietà
         string nome = persona.Nome;

         Console.WriteLine(nome); // Output: Mario Rossi
      }
}

Proprietà automatiche

C# supporta anche le proprietà automatiche, che semplificano ulteriormente la definizione delle proprietà senza dover dichiarare un campo privato separato:

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

Con le proprietà automatiche, il compilatore genera automaticamente un campo privato dietro le quinte. Questo è utile quando non hai bisogno di una logica aggiuntiva nei metodi get o set.

Proprietà di sola lettura e di sola scrittura

Puoi creare proprietà di sola lettura o di sola scrittura omettendo rispettivamente set o get:

public class Persona
{
               private string nome;

               private string cognome;

               // Proprietà di sola lettura
               public string Nome
               {
                   get
                   {
                        return nome;
                   }
              }

             // Proprietà di sola scrittura
             public string Cognome
             {
                   set
                   {
                     cognome = value;
                   }

}
}

Conclusione

Le proprietà in C# sono potenti strumenti per gestire l’accesso ai dati di una classe, fornendo un modo sicuro e controllato per leggere e scrivere i valori dei campi privati. Spero che questa spiegazione ti sia stata utile per comprendere le basi delle proprietà in C#.

LINK AI PRECEDENTI POST

LINK AL CODICE SU GITHUB