C# Language Inizializzatori di proprietà automatica


Esempio

introduzione

Le proprietà possono essere inizializzate con l'operatore = dopo la chiusura } . La classe Coordinate seguito mostra le opzioni disponibili per inizializzare una proprietà:

6.0
public class Coordinate
{ 
    public int X { get; set; } = 34; // get or set auto-property with initializer

    public int Y { get; } = 89;      // read-only auto-property with initializer              
}

Accessors con diversa visibilità

È possibile inizializzare le proprietà automatiche che hanno visibilità diversa sui loro accessor. Ecco un esempio con un setter protetto:

    public string Name { get; protected set; } = "Cheeze";

L'accessor può anche essere internal , internal protected o private .


Proprietà di sola lettura

Oltre alla flessibilità con la visibilità, puoi anche inizializzare le proprietà automatiche di sola lettura. Ecco un esempio:

    public List<string> Ingredients { get; } = 
        new List<string> { "dough", "sauce", "cheese" };

Questo esempio mostra anche come inizializzare una proprietà con un tipo complesso. Inoltre, le proprietà automatiche non possono essere solo di scrittura, quindi preclude anche l'inizializzazione di sola scrittura.


Vecchio stile (pre C # 6.0)

Prima del C # 6, questo richiedeva un codice molto più dettagliato. Stavamo usando una variabile extra chiamata backing property per la proprietà per dare un valore predefinito o per inizializzare la proprietà pubblica come di seguito,

6.0
public class Coordinate
{
    private int _x = 34;
    public int X { get { return _x; } set { _x = value; } }

    private readonly int _y = 89;
    public int Y { get { return _y; } }
    
    private readonly int _z;
    public int Z { get { return _z; } }

    public Coordinate()
    {
        _z = 42;
    }
}

Nota: prima di C # 6.0, era ancora possibile inizializzare le proprietà di auto-implementazione di lettura e scrittura (proprietà con getter e setter) all'interno del costruttore, ma non era possibile inizializzare la proprietà in linea con la sua dichiarazione

Visualizza la demo


uso

Gli inizializzatori devono valutare le espressioni statiche, proprio come gli inizializzatori di campo. Se è necessario fare riferimento a membri non statici, è possibile inizializzare le proprietà in costruttori come in precedenza oppure utilizzare proprietà con corpo di espressione. Le espressioni non statiche, come quella seguente (commentate), generano un errore del compilatore:

// public decimal X { get; set; } = InitMe();  // generates compiler error

decimal InitMe() { return 4m; }

Ma i metodi statici possono essere utilizzati per inizializzare le proprietà automatiche:

public class Rectangle
{
    public double Length { get; set; } = 1;
    public double Width { get; set; } = 1;
    public double Area { get; set; } = CalculateArea(1, 1);

    public static double CalculateArea(double length, double width)
    {
        return length * width;
    }
}

Questo metodo può essere applicato anche a proprietà con diversi livelli di accesso:

public short Type { get; private set; } = 15;

L'inizializzatore della proprietà automatica consente l'assegnazione di proprietà direttamente all'interno della dichiarazione. Per le proprietà di sola lettura, si prende cura di tutti i requisiti richiesti per garantire che la proprietà sia immutabile. Si consideri, ad esempio, la classe FingerPrint nel seguente esempio:

public class FingerPrint
{
  public DateTime TimeStamp { get; } = DateTime.UtcNow;

  public string User { get; } =
    System.Security.Principal.WindowsPrincipal.Current.Identity.Name;

  public string Process { get; } =
    System.Diagnostics.Process.GetCurrentProcess().ProcessName;
}

Visualizza la demo


Note cautelative

Fai attenzione a non confondere gli inizializzatori di auto-proprietà o di campo con metodi di espressione del corpo simili che utilizzano => anziché = , e campi che non includono { get; } .

Ad esempio, ciascuna delle seguenti dichiarazioni è diversa.

public class UserGroupDto
{
    // Read-only auto-property with initializer:       
    public ICollection<UserDto> Users1 { get; } = new HashSet<UserDto>();
    
    // Read-write field with initializer:
    public ICollection<UserDto> Users2 = new HashSet<UserDto>();

    // Read-only auto-property with expression body:
    public ICollection<UserDto> Users3 => new HashSet<UserDto>();
}

Manca { get; } nella dichiarazione della proprietà risulta in un campo pubblico. Sia gli utenti di proprietà di Users1 lettura Users1 che quelli di lettura-scrittura Users2 vengono inizializzati solo una volta, ma un campo pubblico consente di modificare l'istanza di raccolta dall'esterno della classe, che di solito non è desiderabile. La modifica di una proprietà automatica di sola lettura con il corpo di un'espressione in proprietà di sola lettura con l'inizializzatore richiede non solo la rimozione di > da => , ma l'aggiunta di { get; } .

Il diverso simbolo ( => invece di = ) in Users3 risulta in ogni accesso alla proprietà che restituisce una nuova istanza di HashSet<UserDto> che, mentre C # valido (dal punto di vista del compilatore) è improbabile che sia il comportamento desiderato quando usato per un membro della collezione.

Il codice sopra è equivalente a:

public class UserGroupDto
{
    // This is a property returning the same instance
    // which was created when the UserGroupDto was instantiated.
    private ICollection<UserDto> _users1 = new HashSet<UserDto>();
    public ICollection<UserDto> Users1 { get { return _users1; } }

    // This is a field returning the same instance
    // which was created when the UserGroupDto was instantiated.
    public virtual ICollection<UserDto> Users2 = new HashSet<UserDto>();

    // This is a property which returns a new HashSet<UserDto> as
    // an ICollection<UserDto> on each call to it.
    public ICollection<UserDto> Users3 { get { return new HashSet<UserDto>(); } }
}