Utilizzo delle proprietà (Guida per programmatori C#)

Nelle proprietà vengono combinati alcuni aspetti dei campi e dei metodi. Dal punto di vista dell'utente di un oggetto, una proprietà è un campo e l'accesso alla proprietà richiede esattamente la stessa sintassi. Dal punto di vista del responsabile dell'implementazione di una classe, una proprietà è costituita da uno o due blocchi di codice che rappresentano una funzione di accesso get e/o set. Il blocco di codice relativo alla funzione di accesso get viene eseguito quando la proprietà viene letta, mentre il blocco di codice relativo alla funzione di accesso set viene eseguito quando viene assegnato un nuovo valore alla proprietà. Una proprietà in cui non è definita la funzione di accesso set è considerata in sola lettura. Una proprietà in cui non è definita la funzione di accesso get è considerata in sola scrittura. Una proprietà con entrambe le funzioni di accesso è considerata di lettura/scrittura.

Al contrario dei campi, le proprietà non sono classificate come variabili. Pertanto, non è possibile passare una proprietà come parametro ref (Riferimenti per C#) o out (Riferimenti per C#).

Le proprietà possono essere utilizzate per diversi scopi, ad esempio per convalidare i dati prima di consentire una modifica, per esporre in modo trasparente i dati in una classe in cui tali dati vengono in realtà recuperati da un'altra origine, ad esempio un database, per eseguire un'azione in caso di modifica dei dati, ad esempio la generazione di un evento, o per modificare il valore di altri campi.

Le proprietà vengono dichiarate all'interno del blocco della classe specificando il livello di accesso del campo, seguito dal tipo e dal nome della proprietà e da un blocco di codice in cui sono dichiarate le funzioni di accesso get e/o set. Di seguito è riportato un esempio.

public class Date
{
    private int month = 7;  // Backing store

    public int Month
    {
        get
        {
            return month;
        }
        set
        {
            if ((value > 0) && (value < 13))
            {
                month = value;
            }
        }
    }
}

In questo esempio Month viene dichiarato come proprietà in modo che la funzione di accesso set possa assicurare che il valore Month sia impostato tra 1 e 12. La proprietà Month utilizza un campo privato per tenere traccia del valore effettivo. La posizione reale dei dati di una proprietà è spesso indicata con il termine "archivio di backup" della proprietà. In genere, le proprietà utilizzano campi privati come archivio di backup. L'utilizzo dei campi privati assicura che il campo possa essere modificato soltanto chiamando la proprietà. Per ulteriori informazioni sulle restrizioni per l'accesso pubblico e privato, vedere Modificatori di accesso (Guida per programmatori C#).

Le proprietà implementate automaticamente forniscono sintassi semplificata per le dichiarazioni di proprietà semplici. Per ulteriori informazioni, vedere Proprietà implementate automaticamente (Guida per programmatori C#).

Funzione di accesso get

Il corpo della funzione di accesso get è simile a quello di un metodo. Tale funzione deve restituire un valore del tipo di proprietà. L'esecuzione della funzione di accesso get equivale alla lettura del valore del campo. Ad esempio, durante la restituzione della variabile privata dalla funzione di accesso get, se le ottimizzazioni sono attivate, la chiamata al metodo della funzione di accesso get viene resa inline dal compilatore, in modo da evitare un sovraccarico per la chiamata al metodo. Tuttavia, un metodo virtuale della funzione di accesso get non può essere reso inline poiché il compilatore non conosce, in fase di compilazione, quale metodo può essere effettivamente chiamato in fase di esecuzione. Di seguito è riportata una funzione di accesso get che restituisce il valore di un campo privato name:

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
    }
}

Quando si fa riferimento alla proprietà, eccetto come destinazione di un'assegnazione, viene chiamata la funzione di accesso get per leggere il valore della proprietà. Di seguito è riportato un esempio.

Person person = new Person();
//...

System.Console.Write(person.Name);  // the get accessor is invoked here

La funzione di accesso get deve terminare con un'istruzione return o throw e il controllo non può uscire dal corpo della funzione di accesso.

È preferibile evitare di cambiare lo stato dell'oggetto tramite la funzione di accesso get. Ad esempio, la seguente funzione di accesso produce l'effetto collaterale di cambiare lo stato dell'oggetto ogni volta che si accede al campo number.

private int number;
public int Number
{
    get
    {
        return number++;   // Don't do this
    }
}

La funzione di accesso get può essere utilizzata per restituire il valore del campo oppure per calcolarlo e restituirlo. Di seguito è riportato un esempio.

class Employee
{
    private string name;
    public string Name
    {
        get
        {
            return name != null ? name : "NA";
        }
    }
}

Nel segmento di codice precedente, se non si assegna un valore alla proprietà Name, verrà restituito il valore NA.

Funzione di accesso set

La funzione di accesso set è simile a un metodo che restituisce un valore di tipo void. Utilizza un parametro implicito denominato value, il cui tipo corrisponde al tipo della proprietà. Nell'esempio di codice riportato di seguito viene aggiunta una funzione di accesso set alla proprietà Name:

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

Quando si assegna un valore alla proprietà, la funzione di accesso set viene richiamata tramite un argomento che fornisce il nuovo valore. Di seguito è riportato un esempio.

Person person = new Person();
person.Name = "Joe";  // the set accessor is invoked here                

System.Console.Write(person.Name);  // the get accessor is invoked here

Non è possibile utilizzare il nome del parametro implicito (value) per una dichiarazione di variabile locale in una funzione di accesso set.

Note

Le proprietà possono essere contrassegnate come public, private, protected, internal o protected internal. Questi modificatori di accesso definiscono il modo in cui gli utenti della classe possono accedere alla proprietà. Le funzioni di accesso get e set per la stessa proprietà possono avere modificatori di accesso differenti. Ad esempio, la funzione di accesso get può essere public per consentire l'accesso in sola lettura dall'esterno del tipo, mentre la funzione di accesso set può essere private o protected. Per ulteriori informazioni, vedere Modificatori di accesso (Guida per programmatori C#).

Una proprietà può essere dichiarata statica utilizzando la parola chiave static. In questo modo la proprietà sarà sempre disponibile ai chiamanti, anche se non esiste alcuna istanza della classe. Per ulteriori informazioni, vedere Classi statiche e membri di classi statiche (Guida per programmatori C#).

Una proprietà può essere contrassegnata come virtuale utilizzando la parola chiave virtual. In questo modo le classi derivate possono eseguire l'override del comportamento della proprietà utilizzando la parola chiave override. Per ulteriori informazioni sulle opzioni, vedere Ereditarietà (Guida per programmatori C#).

Una proprietà che esegue l'override di una proprietà virtuale può anche essere contrassegnata come sealed, per indicare alle classi derivate che la proprietà non è più virtuale. Infine, una proprietà può essere dichiarata abstract. Ciò significa che non vi è implementazione nella classe e che le classi derivate devono scrivere la propria implementazione. Per ulteriori informazioni sulle opzioni, vedere Classi e membri delle classi astratte e sealed (Guida per programmatori C#).

Nota

Non è possibile utilizzare un modificatore virtual (Riferimenti per C#), abstract (Riferimenti per C#) o override (Riferimenti per C#) su una funzione di accesso di una proprietà statica.

Esempio

Nell'esempio seguente vengono illustrate le proprietà di istanza, static e in sola lettura. Viene inoltre accettato l'inserimento del nome del dipendente (employee) dalla tastiera, incrementato NumberOfEmployees di 1, quindi vengono visualizzati il nome e il numero del dipendente.

public class Employee
{
    public static int NumberOfEmployees;
    private static int counter;
    private string name;

    // A read-write instance property:
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    // A read-only static property:
    public static int Counter
    {
        get { return counter; }
    }

    // A Constructor:
    public Employee()
    {
        // Calculate the employee's number:
        counter = ++counter + NumberOfEmployees;
    }
}

class TestEmployee
{
    static void Main()
    {
        Employee.NumberOfEmployees = 107;
        Employee e1 = new Employee();
        e1.Name = "Claude Vige";

        System.Console.WriteLine("Employee number: {0}", Employee.Counter);
        System.Console.WriteLine("Employee name: {0}", e1.Name);
    }
}
/* Output:
    Employee number: 108
    Employee name: Claude Vige
*/

In questo esempio viene illustrato come accedere a una proprietà in una classe base nascosta da un'altra proprietà con lo stesso nome in una classe derivata.

public class Employee
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

public class Manager : Employee
{
    private string name;

    // Notice the use of the new modifier:
    public new string Name
    {
        get { return name; }
        set { name = value + ", Manager"; }
    }
}

class TestHiding
{
    static void Main()
    {
        Manager m1 = new Manager();

        // Derived class property.
        m1.Name = "John";

        // Base class property.
        ((Employee)m1).Name = "Mary";

        System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
        System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
    }
}
/* Output:
    Name in the derived class is: John, Manager
    Name in the base class is: Mary
*/

Di seguito sono indicati alcuni aspetti importanti dell'esempio precedente.

  • La proprietà Name nella classe derivata nasconde la proprietà Name nella classe base. In questo caso, il modificatore new viene utilizzato nella dichiarazione della proprietà nella classe derivata:

    public new string Name
    
  • Il cast (Employee) è utilizzato per accedere alla proprietà nascosta nella classe base:

    ((Employee)m1).Name = "Mary";
    

    Per ulteriori informazioni su come nascondere i membri, vedere Modificatore new (Riferimenti per C#).

Nell'esempio che segue le due classi Cube e Square implementano una classe astratta Shape ed eseguono l'override della proprietà astratta Area. Si noti l'uso del modificatore override nelle proprietà. Il programma accetta il membro side come un input e calcola le aree del quadrato e del cubo. Inoltre, accetta l'area come un input e calcola il membro side corrispondente per il quadrato e il cubo.

abstract class Shape
{
    public abstract double Area
    {
        get;
        set;
    }
}

class Square : Shape
{
    public double side;

    public Square(double s)  //constructor
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return side * side;
        }
        set
        {
            side = System.Math.Sqrt(value);
        }
    }
}

class Cube : Shape
{
    public double side;

    public Cube(double s)
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return 6 * side * side;
        }
        set
        {
            side = System.Math.Sqrt(value / 6);
        }
    }
}

class TestShapes
{
    static void Main()
    {
        // Input the side:
        System.Console.Write("Enter the side: ");
        double side = double.Parse(System.Console.ReadLine());

        // Compute the areas:
        Square s = new Square(side);
        Cube c = new Cube(side);

        // Display the results:
        System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
        System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
        System.Console.WriteLine();

        // Input the area:
        System.Console.Write("Enter the area: ");
        double area = double.Parse(System.Console.ReadLine());

        // Compute the sides:
        s.Area = area;
        c.Area = area;

        // Display the results:
        System.Console.WriteLine("Side of the square = {0:F2}", s.side);
        System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
    }
}
/* Example Output:
    Enter the side: 4
    Area of the square = 16.00
    Area of the cube = 96.00

    Enter the area: 24
    Side of the square = 4.90
    Side of the cube = 2.00
*/

Vedere anche

Riferimenti

Proprietà (Guida per programmatori C#)

Proprietà dell'interfaccia (Guida per programmatori C#)

Proprietà implementate automaticamente (Guida per programmatori C#)

Concetti

Guida per programmatori C#