Condividi tramite


Proprietà (Guida per programmatori C#)

Una proprietà è un membro che fornisce un meccanismo flessibile per leggere, scrivere o calcolare il valore di un campo dati. Le proprietà vengono visualizzate come membri dati pubblici, ma vengono implementate come metodi speciali denominati funzioni di accesso. Questa funzione consente ai chiamanti di accedere facilmente ai dati e di alzare di livello la sicurezza e la flessibilità dei dati. La sintassi delle proprietà è un'estensione naturale dei campi. Un campo definisce una posizione di archiviazione:

public class Person
{
    public string? FirstName;

    // Omitted for brevity.
}

Proprietà implementate automaticamente

La definizione di una proprietà contiene le dichiarazioni di una funzione di accesso get e set che recupera e assegna il valore della proprietà:

public class Person
{
    public string? FirstName { get; set; }

    // Omitted for brevity.
}

L'esempio precedente mostra una proprietà implementata automaticamente. Il compilatore genera un campo sottostante nascosto per la proprietà . Il compilatore implementa anche il corpo degli accessor get e set. Tutti gli attributi vengono applicati alla proprietà implementata automaticamente. È possibile applicare l'attributo al campo sottostante generato dal compilatore specificando il tag field: sull'attributo .

È possibile inizializzare una proprietà a un valore diverso da quello predefinito impostando un valore dopo la parentesi graffa di chiusura della proprietà. Per la proprietà FirstName, è preferibile usare come valore iniziale una stringa vuota anziché null. È necessario specificarlo, come illustrato nel codice seguente:

public class Person
{
    public string FirstName { get; set; } = string.Empty;

    // Omitted for brevity.
}

Proprietà supportate dal campo

In C# 13 è possibile aggiungere la convalida o un'altra logica nella funzione di accesso per una proprietà usando la funzionalità di anteprima della parola chiave field. La field parola chiave accede al campo sottostante sintetizzato dal compilatore per una proprietà. Consente di scrivere una funzione di accesso alle proprietà senza dichiarare esplicitamente un campo sottostante separato.

public class Person
{
    public string? FirstName 
    { 
        get;
        set => field = value.Trim(); 
    }

    // Omitted for brevity.
}

Importante

La field parola chiave è una funzionalità di anteprima in C# 13. È necessario usare .NET 9 e impostare l'elemento <LangVersion> su preview nel file di progetto per usare la field parola chiave contestuale.

È consigliabile prestare attenzione usando la funzionalità della parola chiave field in una classe con un campo denominato field. La nuova field parola chiave oscura un campo denominato field nell'ambito di un accessore di proprietà. È possibile modificare il nome della field variabile oppure usare il @ token per fare riferimento all'identificatore field come @field. Per altre informazioni, leggere la specifica della funzionalità per la field parola chiave .

Proprietà obbligatorie

Nell'esempio precedente, un chiamante può creare un Person utilizzando il costruttore predefinito, senza impostare la proprietà FirstName. La proprietà ha modificato il tipo in una stringa nullable. A partire da C# 11, è possibile richiedere ai chiamanti di impostare una proprietà:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName) => FirstName = firstName;

    public required string FirstName { get; init; }

    // Omitted for brevity.
}

Il codice precedente apporta due modifiche alla classe Person. In primo luogo, la dichiarazione di proprietà FirstName include il modificatore required. Questo significa che qualsiasi codice che crea un nuovo Person deve impostare questa proprietà utilizzando un inizializzatore di oggetto. In secondo luogo, il costruttore che accetta un parametro firstName ha l'attributo System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute. Questo attributo informa il compilatore che questo costruttore imposta tutti i membri required. I chiamanti che usano questo costruttore non sono tenuti a impostare le proprietà required con un inizializzatore di oggetto.

Importante

Non confondere required con non-nullable. Una proprietà required può essere impostata su null o default. Se il tipo non ammette i valori Null, come string in questi esempi, il compilatore genera un avviso.

var aPerson = new Person("John");
aPerson = new Person { FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();

Definizioni del corpo dell'espressione

Le funzioni di accesso alle proprietà sono spesso costituite da istruzioni a riga singola. Le funzioni di accesso assegnano o restituiscono il risultato di un'espressione. È possibile implementare queste proprietà come membri con corpo di espressione. Le definizioni del corpo dell'espressione consistono nel token => seguito dall'espressione da assegnare o recuperare dalla proprietà.

Le proprietà di sola lettura possono implementare il metodo di accesso get come membro a corpo di espressione. L'esempio seguente implementa la proprietà Name di sola lettura come membro con corpo di espressione:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    public string Name => $"{FirstName} {LastName}";

    // Omitted for brevity.
}

La proprietà Name è una proprietà di calcolo. Non esiste alcun campo sottostante per Name. La proprietà lo calcola ogni volta.

Controllo di accesso

Gli esempi precedenti hanno mostrato proprietà di lettura/scrittura. È possibile anche creare proprietà di sola lettura o assegnare un'accessibilità diversa agli accessor set e get. Si supponga che la Person classe debba abilitare solo la modifica del valore della FirstName proprietà da altri metodi nella classe . È possibile impostare l'accessibilità all'accessore private invece di internal o public.

public class Person
{
    public string? FirstName { get; private set; }

    // Omitted for brevity.
}

La proprietà FirstName può essere letta da qualsiasi codice, ma può essere assegnata soltanto dal codice della classe Person.

È possibile aggiungere qualsiasi modificatore di accesso restrittivo alle funzioni di accesso set o get. Un modificatore di accesso su un singolo accessor deve essere più restrittivo rispetto all'accesso della proprietà. Il codice precedente è valido poiché la proprietà FirstName è public e la funzione di accesso set è private. Non è possibile dichiarare una proprietà private con un metodo di accesso public. Le dichiarazioni di proprietà possono anche essere dichiarate protected, internal, protected internal o anche private.

Esistono due modificatori di accesso speciali per le funzioni di accesso set:

  • Una funzione di accesso set può avere init come modificatore di accesso. Tale funzione di accesso set può essere chiamata solo da un inizializzatore di oggetto o dai costruttori del tipo. È più restrittivo di private sull' set accessor.
  • Una proprietà implementata automaticamente può dichiarare un accessore get senza un accessore set. In tal caso, il compilatore consente di chiamare la funzione di accesso set solo dai costruttori del tipo. È più restrittivo rispetto alla funzione di accesso init nella funzione di accesso set.

Modificare la classe Person, come indicato di seguito:

public class Person
{
    public Person(string firstName) => FirstName = firstName;

    public string FirstName { get; }

    // Omitted for brevity.
}

L'esempio precedente richiede ai chiamanti di usare il costruttore che include il parametro FirstName. I chiamanti non possono usare inizializzatori di oggetti per assegnare un valore alla proprietà. Per supportare gli inizializzatori, è possibile sostituire la funzione di accesso set con init, come illustrato nel codice seguente:

public class Person
{
    public Person() { }
    public Person(string firstName) => FirstName = firstName;

    public string? FirstName { get; init; }

    // Omitted for brevity.
}

Questi modificatori vengono spesso usati con il modificatore required per forzare l'inizializzazione corretta.

Proprietà con campi di supporto

È possibile unire il concetto di proprietà calcolata al concetto di campo privato e creare una proprietà con valutazione memorizzata nella cache. Ad esempio, aggiornare la proprietà FullName in modo che la formattazione della stringa avvenga al primo accesso:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Questa implementazione funziona perché le proprietà FirstName e LastName sono di sola lettura. Le persone possono cambiare il nome. L'aggiornamento delle proprietà FirstName e LastName per consentire le funzioni di accesso set richiede di invalidare qualsiasi valore memorizzato nella cache per fullName. Modifichi le funzioni di accesso set delle proprietà FirstName e LastName in modo che il campo fullName sia calcolato di nuovo.

public class Person
{
    private string? _firstName;
    public string? FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            _fullName = null;
        }
    }

    private string? _lastName;
    public string? LastName
    {
        get => _lastName;
        set
        {
            _lastName = value;
            _fullName = null;
        }
    }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

La versione finale valuta la proprietà FullName solo quando necessario. Se valida, viene usata la versione calcolata in precedenza. In caso contrario, il calcolo aggiorna il valore memorizzato nella cache. Non è necessario che gli sviluppatori che usano questa classe siano a conoscenza dei dettagli dell'implementazione. Nessuna di queste modifiche interne ha effetto sull'uso dell'oggetto Persona.

A partire da C# 13, è possibile creare proprietà partial nelle classi partial. La dichiarazione di implementazione per una partial proprietà non può essere una proprietà implementata automaticamente. Una proprietà implementata automaticamente usa la stessa sintassi di una dichiarazione parziale di proprietà.

Proprietà

Le proprietà sono una forma di campi intelligenti in una classe o un oggetto. All'esterno dell'oggetto, vengono visualizzate come campi dell'oggetto. Tuttavia, le proprietà possono essere implementate usando l'intera gamma di funzionalità di C#. È possibile specificare la convalida, un'accessibilità diversa, la valutazione pigrante o qualsiasi altro requisito di cui i tuoi scenari hanno bisogno.

  • Le proprietà semplici che non richiedono codice della funzione di accesso personalizzato possono essere implementate come definizioni del corpo dell'espressione o come proprietà implementate automaticamente.
  • 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 le funzioni 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.

Specifiche del linguaggio C#

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

Vedi anche