Proprietà (Guida per programmatori C#)

Una proprietà è un membro che fornisce un meccanismo flessibile per leggere, scrivere o calcolare il valore di un campo privato. Le proprietà possono essere usate come se fossero membri di dati pubblici, ma sono in realtà metodi speciali denominati funzioni di accesso. Questa caratteristica consente di accedere facilmente ai dati e di alzare di livello la sicurezza e la flessibilità dei metodi.

Panoramica delle proprietà

  • Le proprietà consentono a una classe di esporre un modo pubblico per ottenere e impostare i valori, nascondendo però il codice di implementazione o di verifica.
  • Una funzione di accesso della proprietà get viene usata per restituire il valore della proprietà, mentre una funzione di accesso della proprietà set viene usata per assegnare un nuovo valore. Una funzione di accesso alle proprietà init viene usata per assegnare un nuovo valore solo durante la costruzione di oggetti. Queste funzioni di accesso possono avere diversi livelli di accesso. Per altre informazioni, vedere Limitazione dell'accessibilità delle funzioni di accesso.
  • La parola chiave value viene usata per definire il valore assegnato dalla funzione di accesso set o init.
  • Le proprietà possono essere di lettura/scrittura con entrambe le funzione di accesso get e set, di sola lettura con la funzione di accesso get e senza la funzione di accesso set o di sola scrittura con la funzione di accesso set e senza la funzione di accesso get. Le proprietà di sola scrittura sono rare e vengono in genere usate per limitare l'accesso ai dati sensibili.
  • Le proprietà semplici che non richiedono alcun codice di funzione di accesso personalizzata possono essere implementate come definizioni del corpo dell'espressione o come proprietà implementate automaticamente.

Proprietà con campi sottostanti

Un modello di base per l'implementazione di una proprietà prevede l'uso di un campo sottostante privato per l'impostazione e il recupero del valore della proprietà. La funzione di accesso get restituisce il valore del campo privato e la funzione di accesso set può eseguire una convalida dei dati prima di assegnare un valore al campo privato. Entrambe le funzioni di accesso possono anche eseguire una conversione o un calcolo nei dati prima che siano archiviati o restituiti.

L'esempio seguente illustra il modello. Nell'esempio la classe TimePeriod rappresenta un intervallo di tempo. Internamente la classe archivia l'intervallo di tempo in secondi in un campo privato denominato _seconds. Una proprietà di lettura/scrittura denominata Hours consente al cliente di specificare l'intervallo di tempo in ore. Entrambe le funzioni di accesso get e set eseguono la conversione necessaria tra ore e secondi. Inoltre, la funzione di accesso set convalida i dati e genera ArgumentOutOfRangeException se il numero di ore non è valido.

public class TimePeriod
{
    private double _seconds;

    public double Hours
    {
        get { return _seconds / 3600; }
        set
        {
            if (value < 0 || value > 24)
                throw new ArgumentOutOfRangeException(nameof(value),
                      "The valid range is between 0 and 24.");

            _seconds = value * 3600;
        }
    }
}

È possibile accedere alle proprietà per ottenere e impostare il valore come mostrato nell'esempio seguente:

TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;

// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
// The example displays the following output:
//    Time in hours: 24

Definizioni del corpo dell'espressione

Le funzioni di accesso delle proprietà sono spesso costituite da istruzioni a riga singola che assegnano o restituiscono il risultato di un'espressione. È possibile implementare queste proprietà come membri con corpo di espressione. Le definizioni del corpo dell'espressione sono costituite dal simbolo => seguito dall'espressione per l'assegnazione o il recupero dalla proprietà.

Le proprietà di sola lettura possono implementare la funzione di accesso get come membro con corpo di espressione. In questo caso non viene usata la parola chiave della funzione di accesso get né la parola chiave return. L'esempio seguente implementa la proprietà Name di sola lettura come membro con corpo di espressione.

public class Person
{
    private string _firstName;
    private string _lastName;

    public Person(string first, string last)
    {
        _firstName = first;
        _lastName = last;
    }

    public string Name => $"{_firstName} {_lastName}";
}

Entrambe le funzioni di accesso get e set possono essere implementate come membri con corpo di espressione. In questo caso, è necessario che siano presenti le parole chiave get e set. L'esempio seguente illustra l'uso di definizioni del corpo dell'espressione per entrambe le funzioni di accesso. La parola chiave return non viene usata con la funzione di accesso get.

public class SaleItem
{
    string _name;
    decimal _cost;

    public SaleItem(string name, decimal cost)
    {
        _name = name;
        _cost = cost;
    }

    public string Name
    {
        get => _name;
        set => _name = value;
    }

    public decimal Price
    {
        get => _cost;
        set => _cost = value;
    }
}

Proprietà implementate automaticamente

In alcuni casi, le funzioni di accesso get e set delle proprietà si limitano ad assegnare o a recuperare un valore da un campo sottostante senza includere alcuna logica extra. Usando le proprietà implementate automaticamente è possibile semplificare il codice e fare in modo che il compilatore C# specifichi automaticamente in modo trasparente il campo sottostante.

Se una proprietà ha entrambe le funzioni di accesso get e set (o get e init), entrambe le funzioni devono essere implementate automaticamente. È possibile definire una proprietà implementata automaticamente usando le parole chiave get e set senza specificare alcuna implementazione. L'esempio seguente ripete l'esempio precedente, ad eccezione del fatto che Name e Price sono proprietà implementate automaticamente. L’esempio rimuove anche il costruttore con parametri in modo che gli oggetti SaleItem vengano ora inizializzati con una chiamata al costruttore senza parametri e un inizializzatore di oggetto.

public class SaleItem
{
    public string Name
    { get; set; }

    public decimal Price
    { get; set; }
}

Le proprietà implementate automaticamente possono dichiarare diverse accessibilità per le funzioni di accesso get e set. In genere si dichiara una funzione di accesso get pubblica e una funzione di accesso set privata. Per altre informazioni, vedere l'articolo su limitazione dell'accessibilità delle funzioni di accesso.

Proprietà obbligatorie

A partire da C# 11, è possibile aggiungere il membro required per forzare il codice client a inizializzare qualsiasi proprietà o campo:

public class SaleItem
{
    public required string Name
    { get; set; }

    public required decimal Price
    { get; set; }
}

Per creare un oggetto SaleItem, è necessario impostare entrambe le proprietà Name e Price usando gli inizializzatori di oggetto, come illustrato nel codice seguente:

var item = new SaleItem { Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");

Specifiche del linguaggio C#

Per altre informazioni, vedere Tipi integrali in Specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedi anche