Devo preferire proprietà con o senza campi privati?


16

La base di codice in cui sto lavorando ora ha la convenzione di usare campi privati ​​e proprietà pubbliche. Ad esempio, molte classi hanno i loro membri definiti in questo modo:

// Fields
private double _foo;
private double _bar;
private double _baz;

// Properties
public double Foo
{
    get{ return _foo; }
    set{ _foo = value; }
}

public double Bar
{
    get{ return _bar; }
    set{ _bar = value; }
}

public double Baz
{
    get{ return _baz; }
}

So che questi possono essere riscritti senza le loro proprietà private interne:

public double Foo{ get; set; }
public double Bar{ get; set; }
public double Baz{ get; private set; }

Vorrei qualche input su questo:

  • C'è una buona ragione per preferire lo stile più vecchio, più esplicito rispetto a quello più nuovo, più conciso?
  • Dovrei scrivere nuove classi usando lo stile conciso o devo cercare di abbinare il codice precedente per coerenza? In questo caso vale la coerenza per giustificare il formato precedente?

Vedi questa domanda e risposta .
Peter K.

@PeterK. Informativo. Non risponde se dovrei preoccuparmi o meno di mantenere lo stile del resto del programma o se è un dettaglio abbastanza piccolo da non avere importanza.
KChaloux,

@KChaloux: Capito! Ecco perché è un commento, non una risposta. :-)
Peter K.

@PeterK. Fair 'nuff = p
KChaloux

1
un altro motivo per non cambiare è se qualcosa viene passato sul filo con WCF - le proprietà automatiche hanno problemi di contratto (a causa dei caratteri non validi nei nomi dei campi di supporto creati da .NET)
Leon

Risposte:


16

Ci sono un paio di casi in cui è ancora richiesto il cosiddetto stile "più vecchio":

A: Tipi immutabili usando l'immutabilità fornita dalla lingua. Il readonlymodificatore in C # congela quel valore dopo la costruzione. Non c'è modo di imitare questo con proprietà implementate automaticamente (ancora).

public sealed class FooBarBazInator
{
    private readonly double foo;

    public FooBarBazInator(double foo)
    {
        this.foo = foo;
    }

    public double Foo
    {
        get
        {
            return this.foo;
        }
    }
}

B: I tuoi getter / setter hanno una logica qualsiasi. I codici WPF e Silverlight (e simili) associati ai dati delle tue classi verranno implementati in questo INotifyPropertyChangedmodo:

public class FooBarBazInator : INotifyPropertyChanged
{
    private double foo;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Foo
    {
        get
        {
            return this.foo;
        }

        set
        {
            this.foo = value;
            this.RaisePropertyChanged("Foo");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Oltre a quelli, direi di usare il nuovo stile. Mantiene il codice conciso e offre meno superficie per i bug da insinuare. Inoltre, se dovesse mai essere necessario cambiare per includere la logica, non sarà incompatibile con la firma.


2
Tutti sembrano essere d'accordo sull'andare con il nuovo stile. Ottieni un +1 e il credito di risposta per avermi parlato della necessità di un campo con il readonlymodificatore, che non conoscevo. = D
KChaloux

3
Alcuni (incluso me) considerano le proprietà automatiche con accesso privato "abbastanza buone" per proprietà immutabili. È vero, potrebbero non essere veramente immutabili, ma devi solo stare attento a non usare il setter al di fuori del costruttore.
svick

2
un'altra ragione è se si desidera passare il valore in quanto refnon funziona con le proprietà, quindi è necessario il campo
stijn

1
Uno strumento come Fody può implementare INotifyPropertyChangedsenza la necessità di campi di supporto espliciti. github.com/Fody/PropertyChanged
Sebastian Redl

3
Prendi nota: C # 6 consente "proprietà automatiche solo per getter" che forniscono in una sola riga cosa sta facendo il mio esempio "A".
Jesse C. Slicer,

6

Direi che avere un backing field esplicito è solo un'inutile cruft: rende il tuo codice più lungo e più difficile da leggere. Aggiunge anche potenziale di errore:

public double Bar
{
    get { return _baz; }
    set { _bar = value; }
}

Penso che un errore del genere possa accadere abbastanza facilmente e sarebbe piuttosto difficile da individuare.

E se vuoi coerenza, fallo nell'altro modo: modifica il codice che utilizza i campi di supporto in codice che utilizza proprietà automatiche. Questo è particolarmente facile se usi uno strumento di refactoring come ReSharper (e se non usi qualcosa del genere, penso che dovresti iniziare).

Certo, ci sono ancora casi in cui è necessario avere un backing field, ma penso che non sia rilevante per questa domanda.


L'ho fatto su alcuni dei vecchi campi durante il refactoring del codice ... è una seccatura.
KChaloux,

1

Anche se la domanda è piuttosto vecchia, ho pensato di aggiungere un paio di punti che ho letto da un libro che vale la pena menzionare qui.

  1. I motori di serializzazione runtime persistono il nome dell'archiviato in un flusso serializzato. Il nome del campo di supporto per una proprietà implementata automaticamente (AIP) è determinato dal compilatore e potrebbe effettivamente cambiare il nome di questo campo di supporto ogni volta che si ricompila il codice, annullando la possibilità di deserializzare istanze di qualsiasi tipo che contenga un AIP. Quindi non utilizzare AIP con alcun tipo che si intende serializzare o deserializzare.

  2. Durante il debug, non è possibile impostare un punto di interruzione su un metodo get o set AIP, quindi non è possibile rilevare facilmente quando un'applicazione sta ottenendo o impostando questa proprietà. È possibile impostare punti di interruzione su punti di interruzione implementati manualmente


3
# 1 - La maggior parte dei serializzatori ignora le proprietà / i campi privati ​​per impostazione predefinita; Non ho mai riscontrato i problemi menzionati. # 2 - Questo problema è stato risolto in VS2015 e può essere risolto in VS2013. Vedi questo articolo di Visual Studio Magazine .
Brian,

-3

C'è una buona ragione per preferire lo stile più vecchio, più esplicito rispetto a quello più nuovo, più conciso?

Non proprio. Anche se direi che ogni volta che hai avuto un passaggio attraverso tale proprietà, avresti dovuto usare un campo pubblico per cominciare.

Dovrei scrivere nuove classi usando lo stile conciso o devo cercare di abbinare il codice precedente per coerenza? In questo caso vale la coerenza per giustificare il formato precedente?

Supponendo che tu abbia ignorato i consigli di cui sopra e abbia proprietà passthrough, non mirerei ad abbinare lo stile. Idealmente, dovresti tornare indietro e riformattare il vecchio stile nel nuovo stile per renderlo coerente, ma la possibilità che le persone leggano male quel codice è scarsa.



@svick - Bah. A meno che tu non stia riflettendo sul tipo, non c'è differenza. Se stai esponendo pubblicamente il tipo come interfaccia di servizio o di libreria, esporrai un'interfaccia che richiederà comunque una proprietà. L'OP non sta facendo nessuna di queste cose.
Telastyn,

2
Non vi è alcun motivo tecnico in questi casi limitati. Non dimenticare che le proprietà si comportano diversamente nel debugger, nei diagrammi di classe, in intellisense e proprio quando pensi di non fare riflessioni, il framework .NET lo è. WinForms, WPF e molti altri componenti usano internamente la riflessione e trattano le proprietà separatamente, quindi i consigli sull'uso dei campi pubblici, in ogni caso, saranno scarsamente ricevuti da molti sviluppatori su questo sito.
Kevin McCormick,

1
@KevinMcCormick e il framework si comportano perfettamente (da quello che ho capito) con i campi. Non importa davvero dal momento che ora ci sono proprietà automatiche, ma il problema più grande è rendere le cose pubbliche in primo luogo. Fin troppe persone pensano che il semplice fatto di rendere le proprietà delle cose in qualche modo le assolva dal "non creare campi pubblici".
Telastyn,

2
Il Framework li gestisce in modo diverso: prova a utilizzare un campo pubblico in EF POCO, collegalo a un DataGridView, usa un PropertyGrid, ecc. Ho appena fatto una rapida ricerca nel mio decompilatore per Type.GetProperties / GetProperty e il Framework effettua chiamate a questo metodo centinaia di volte, ma non per GetField. In conclusione, sono diversi e la raccomandazione di utilizzare sempre le proprietà per i dati pubblici si basa in parte su questo fatto. Questo non preclude mai l'utilizzo dei campi, ma quel caso necessita di giustificazione. Tuttavia, l'altro punto è sicuramente vero, esporre i dati pubblici con noncuranza è sempre una cattiva idea.
Kevin McCormick,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.