Come implementare una classe leggera con proprietà implementate automaticamente

Questo esempio illustra come creare una classe leggera non modificabile che serve solo per incapsulare un set di proprietà implementate automaticamente. Usare questo genere di costrutto invece di una struct quando è necessario usare la semantica del tipo riferimento.

È possibile rendere una proprietà non modificabile nei modi seguenti:

  • Dichiarare solo la funzione di accesso get, che rende la proprietà non modificabile ovunque tranne che nel costruttore del tipo.
  • Dichiarare una funzione di accesso init anziché una funzione di accesso set, che rende la proprietà impostabile solo nel costruttore o usando un inizializzatore di oggetti.
  • Dichiarare che la funzione di accesso set deve essere privata. La proprietà è impostabile all'interno del tipo, ma non è modificabile per i consumer.

È possibile aggiungere il modificatore required alla dichiarazione di proprietà per forzare i chiamanti a impostare la proprietà come parte dell'inizializzazione di un nuovo oggetto.

Nell'esempio seguente viene illustrato come una proprietà con solo la funzione di accesso get sia diversa da quella con get e set privato.

class Contact
{
    public string Name { get; }
    public string Address { get; private set; }

    public Contact(string contactName, string contactAddress)
    {
        // Both properties are accessible in the constructor.
        Name = contactName;
        Address = contactAddress;
    }

    // Name isn't assignable here. This will generate a compile error.
    //public void ChangeName(string newName) => Name = newName;

    // Address is assignable here.
    public void ChangeAddress(string newAddress) => Address = newAddress;
}

Esempio

L'esempio seguente illustra due modi per implementare una classe non modificabile che ha implementato automaticamente le proprietà. Ogni modo dichiara una delle proprietà con una funzione di accesso set privata e una delle proprietà solo con get. La prima classe usa un costruttore solo per inizializzare le proprietà e la seconda classe usa un metodo factory statico che chiama un costruttore.

// This class is immutable. After an object is created,
// it cannot be modified from outside the class. It uses a
// constructor to initialize its properties.
class Contact
{
    // Read-only property.
    public string Name { get; }

    // Read-write property with a private set accessor.
    public string Address { get; private set; }

    // Public constructor.
    public Contact(string contactName, string contactAddress)
    {
        Name = contactName;
        Address = contactAddress;
    }
}

// This class is immutable. After an object is created,
// it cannot be modified from outside the class. It uses a
// static method and private constructor to initialize its properties.
public class Contact2
{
    // Read-write property with a private set accessor.
    public string Name { get; private set; }

    // Read-only property.
    public string Address { get; }

    // Private constructor.
    private Contact2(string contactName, string contactAddress)
    {
        Name = contactName;
        Address = contactAddress;
    }

    // Public factory method.
    public static Contact2 CreateContact(string name, string address)
    {
        return new Contact2(name, address);
    }
}

public class Program
{
    static void Main()
    {
        // Some simple data sources.
        string[] names = ["Terry Adams","Fadi Fakhouri", "Hanying Feng",
                            "Cesar Garcia", "Debra Garcia"];
        string[] addresses = ["123 Main St.", "345 Cypress Ave.", "678 1st Ave",
                                "12 108th St.", "89 E. 42nd St."];

        // Simple query to demonstrate object creation in select clause.
        // Create Contact objects by using a constructor.
        var query1 = from i in Enumerable.Range(0, 5)
                    select new Contact(names[i], addresses[i]);

        // List elements cannot be modified by client code.
        var list = query1.ToList();
        foreach (var contact in list)
        {
            Console.WriteLine("{0}, {1}", contact.Name, contact.Address);
        }

        // Create Contact2 objects by using a static factory method.
        var query2 = from i in Enumerable.Range(0, 5)
                        select Contact2.CreateContact(names[i], addresses[i]);

        // Console output is identical to query1.
        var list2 = query2.ToList();

        // List elements cannot be modified by client code.
        // CS0272:
        // list2[0].Name = "Eugene Zabokritski";
    }
}

/* Output:
    Terry Adams, 123 Main St.
    Fadi Fakhouri, 345 Cypress Ave.
    Hanying Feng, 678 1st Ave
    Cesar Garcia, 12 108th St.
    Debra Garcia, 89 E. 42nd St.
*/

Il compilatore crea campi di backup per ogni proprietà implementata automaticamente. I campi non sono accessibili direttamente dal codice sorgente.

Vedi anche