Utilizzo di una proprietà auto-implementata privata rispetto a un campo privato

2

Se ho bisogno di campi privati semplici, c'è qualche ragione per cui non dovrei semplicemente fare una convenzione per usare invece proprietà private, auto-implementate?

Ad esempio, potrei fare questo:

private MyClass _foo;

o potrei fare questo:

private MyClass Foo { get; set; }

Sembra che l'unica volta in cui ho bisogno di campi effettivi è quando sto facendo qualcosa come caricamento pigro:

private MyClass Foo
{
    get
    {
        if (_foo == null) _foo = new MyClass();
        return _foo;
    }
}
    
posta rory.ap 06.10.2015 - 17:29
fonte

2 risposte

3

Le due caratteristiche dei campi che ritengo potresti incontrare più comunemente che potresti perdere convertendole in proprietà sono le seguenti:

  1. Non puoi modificare i membri di un valore di una proprietà se si tratta di un tipo di valore.

    // Rectangle is a value type:
    struct Rectangle { int X, Y, Width, Height; }
    
    Rectangle rect;
    Rectangle RectProperty { get; set; }
    
    void Test()
    {
        // This works with a field:
        rect.X = 45;
    
        // but fails with a property:
        RectProperty.X = 45; // compiler error
    
        // The only way to update a value-type property 
        // is to construct & assign a completely new value:
        RectProperty = new Rectangle(45, RectProperty.Y, RectProperty.Width, RectProperty.Height);
    }
    
  2. Non puoi passare una proprietà come parametro out o ref

    int field;
    int SomeProperty { get; set; }
    
    void Test()
    {
        // Works with a field:
        int.TryParse("some text", out field); 
    
        // but fails with a property:
        int.TryParse("some text", out SomeProperty); // compiler error.
    
        // you need to create temporary storage instead:
        int x;
        if (int.TryParse("some text", out x)) { SomeProperty = x; }
    }
    

Se nessuno di questi è un problema per te, probabilmente non noterai la differenza. Ci sono naturalmente altre differenze se stai riflettendo sul tuo tipo, o usando le librerie che riflettono sul tuo tipo e ti aspetti che le cose siano proprietà o campi, ecc.

    
risposta data 06.10.2015 - 23:06
fonte
1

Quando si tratta di proprietà pubbliche, il motivo comune per cui si fa

public MyClass Foo { get; set; }

anziché

public MyClass _foo;

è che quest'ultimo rispetta meglio il principio di apertura / chiusura: se in seguito dovrai aggiungere guardie / caricamento lento ecc. a _foo , quest'ultimo richiede una modifica all'API.

Con campi / proprietà privati però, questo non si applica. I meccanismi interni della tua classe sono completamente aperti alla riscrittura in ogni momento. Quindi se lo fai

private MyClass Foo { get; set; }

anziché

private MyClass _foo;

quindi, come dice Mati Cicero nel suo commento, finisci semplicemente per inquinare la tua IL risultante con metodi getter e setter inutili.

Prendendo il tuo esempio di caricamento lazy, puoi creare una proprietà helper molto succinta a setup pigro _foo usando C # 6:

private MyClass _foo;
private MyClass Foo => _foo ?? (_foo = new MyClass());

La compattezza della sintassi, e quindi la mancanza di rumore, rende discutibile i vantaggi del caricamento pigro tramite una proprietà migliore rispetto all'utilizzo di un metodo di supporto. Come dimostrato dalla lunghezza del tuo esempio, l'uso di un metodo di supporto era probabilmente una soluzione migliore prima della v6.

L'altro utilizzo possibile con C # 6 è in sostituzione:

private readonly MyClass _bar = new MyClass();

con

private MyClass Bar { get; } = new MyClass();

Se quest'ultimo è più leggibile è tuttavia altamente discutibile; discutibilmente entrambi crea un getter inutile e rende l'intenzione del codice meno chiara.

    
risposta data 07.10.2015 - 15:39
fonte

Leggi altre domande sui tag