PROPERTIES IN C#

C sharpProperties in C# are the mechanism that the language provides us with to accomplish encapsulation of data.
We saw in the previous post how it is possible to encapsulate a certain variable defined within a class, making it private, and implementing two public methods that allow read and write access to the variable from outside, respectively.
I report the code:

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)
        {
                     
        }
    }
}

This way of making attributes or instance variables private allows the attribute management to be hidden from the outside world, in fact by defining two public methods that in jargon are called Getter and Setter the variable before presenting it to the outside can in the methods just mentioned write additional code such as validation. Since these are frequent operations C# comes to us with properties which are the mechanism for accomplishing encapsulation. Let us see how to declare and implement a 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)
        {
                     
        }
    }
}

A public property having by convention the same name as the attribute but with a capital letter is declared, and a block of code is opened in which the Getter and Setter methods are replaced with the get and set keywords. Also defined is the value keyword that behind the scenes accesses the new value passed in. In the get and set code blocks nothing prohibits us from writing additional code.

HOW TO USE THEM

After defining a property let’s see how it is used from the outside. I will give you the code

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.          
        }
    }
}

As you see first you create an instance of the Person class then you access the Name property.

BACKING FIELD OF A PROPERTY IN C SHARP

When we declare a property the backing field i.e. the private variable private string nome is not mandatory to declare it, also properties have access modifiers, in the example I gave you above the property is defined public so get e set will inherit that modifier, however we can change the default behavior for example by implementing a private set. This means that the property will be read-only and therefore can be set only within the class.

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)
        {
                  
        }
    }
}

SELF IMPLEMENTED PROPERTY

If we do not implement code in the get and set it is possible to further condense a property in the following way:

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 that case the compiler will be the one to generate behind the scenes the private field i.e. the backing field and the rest of the property code.
You can also specify a default value in the following way:

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

It is possible to initialize properties in one shot with this syntax:

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

LET’S TAKE THE PREVIOUS EXAMPLE CODE AND MODIFY IT USING THE PROPERTIES

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

FURTHER INFORMATION

Properties in C# are an elegant way to access the private fields of a class. They allow you to control the reading and writing of data safely and are a fundamental part of encapsulation in object-oriented programming. Here is a simple explanation with an example:

What is a property?

A property in C# is a member of a class that provides a flexible mechanism for reading, writing, or computing the value of a private field. A property can be read-write, read-only, or write-only.

Basic syntax

Here is an example of a class with a property:

public class Persona
{

         // Private field

         private string nome;
         //Public property

         public string Nome

         {

           get {

                return nome;
           }

           set {

                nome = value;

           }
        }
}

Explanation of the example

1. Private field: private string name

  • This is a private field of the Persona class. It is private, so it can only be accessed within the class itself.

Public property: public string Nome { get; set; }

  • get is an accessor that returns the value of the private field nome.
  • set is a modifier that sets the value of the private field nome.
  • This property allows the nome value to be read and written from outside the class, but via the get and set methods.

Use of the property

Here’s how you can use this property:

public class Program

{

    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

         }

}

Automatic properties

C# also supports automatic properties, which further simplifies the definition of properties without having to declare a separate private field:

public class Persona {

   public string Nome { get; set; }

}

With automatic properties, the compiler automatically generates a private field behind the scenes. This is useful when you don’t need additional logic in the get or set methods.

Read-only and write-only properties

You can create read-only or write-only properties by omitting set or get, respectively:

public class Persona
{

       private string nome;
       // Read-only property

       public string Nome
       {

        get {

            return nome;

        }

      }

      // Write-only property

       public string Cognome
       {

          set {

               cognome = value;
          }

}

}

Conclusion

Properties in C# are powerful tools for managing access to a class’s data, providing a safe and controlled way to read and write private field values. I hope this explanation has been helpful to you in understanding the basics of properties in C#.

LINKS TO PREVIOUS POSTS

LINK TO THE CODE ON GITHUB