Campi pubblici e proprietà automatiche


353

Ci viene spesso detto che dovremmo proteggere l'incapsulamento creando metodi getter e setter (proprietà in C #) per i campi di classe, invece di esporre i campi al mondo esterno.

Ma ci sono molte volte in cui un campo è lì per contenere un valore e non richiede alcun calcolo per ottenere o impostare. Per questi faremmo tutti questo numero:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Bene, ho una confessione, non potevo sopportare di scrivere tutto questo (davvero, non doveva scriverlo, doveva guardarlo), quindi sono diventato un ladro e ho usato campi pubblici.

Poi arriva C # 3.0 e vedo che hanno aggiunto proprietà automatiche:

public class Book
{
    public string Title {get; set;} 
}

che è più ordinato, e ne sono grato, ma davvero, cosa c'è di così diverso che fare un campo pubblico?

public class Book
{
    public string Title;
}


6
Ho convertito un feild in una proprietà solo per poter impostare un breakpoint sul setter
Ian Ringrose

1
Tendo a trasformare tutto ciò che non è privato in una proprietà, poiché realizzare in fondo alla strada che devo trasformare un campo in una proprietà ha portato a un inutile mal di testa. Proprietà, campi e metodi. Oh mio! chiama un'incompatibilità che mi ha morso in passato.
Steven Wexler,

2
Lo propsnippet di codice rende veloce la creazione di proprietà. Basta digitare propquindi la scheda.
Tono Nam

Risposte:


175

In una domanda correlata che avevo qualche tempo fa, c'era un link a un post sul blog di Jeff, che spiegava alcune differenze.

Proprietà vs. variabili pubbliche

  • Reflection funziona in modo diverso su variabili e proprietà, quindi se si fa affidamento su reflection, è più semplice utilizzare tutte le proprietà.
  • Non è possibile eseguire il databind rispetto a una variabile.
  • La modifica di una variabile in una proprietà è una rottura. Per esempio:

    TryGetTitle(out book.Title); // requires a variable

24
"La modifica di una variabile in una proprietà è un cambiamento decisivo." Questo ovviamente si applica solo quando si scrive una libreria riutilizzabile, cosa che la maggior parte degli sviluppatori non sta facendo.
Steven,

30
Inoltre, le proprietà, anche le proprietà automatiche, possono essere virtuali, dove i campi non possono. Pertanto, una classe base può avere una semplice implementazione del backing field come prodotta dal compilatore per un prop propulsore, mentre le classi derivate possono eseguire ulteriori validazioni o altre logiche / calcoli.
KeithS

28
Inoltre un campo è una variabile e può essere passato per riferimento ( refo outparola chiave), mentre una proprietà è una coppia di accessori e non può essere passata per riferimento. Ad esempio, bool success = TryGetMyTitle(out myBook.Title);quali usi outfunzioneranno con un campo e non con una proprietà. Questo è un chiaro esempio del perché il passaggio dal campo alla proprietà è un cambiamento radicale!
Jeppe Stig Nielsen,

2
@KyleBaran No, non ha molto senso perché una proprietà è una coppia di metodi di accesso, non una variabile. Una cosa normale da fare è dichiarare una variabile locale (possibilmente leggere la proprietà e inserirne il valore nella variabile locale), passare la variabile locale come ref/ out, quindi impostare la proprietà sul valore che la variabile locale ha allora. Ma poi il metodo chiamato non accede direttamente alla proprietà, ma accede alla variabile locale che hai creato lì.
Jeppe Stig Nielsen,

5
@theberserker True, anche se in C # 6 puoi fare public int Foo { get; }ciò che creerà una proprietà automatica con un campo di supporto di sola lettura.
Michael Stum

83

Ignorando i problemi dell'API, la cosa che trovo più preziosa nell'uso di una proprietà è il debug.

Il debugger CLR non supporta i punti di interruzione dei dati (la maggior parte dei debugger nativi lo fanno). Quindi non è possibile impostare un punto di interruzione sulla lettura o scrittura di un determinato campo su una classe. Ciò è molto limitante in alcuni scenari di debug.

Poiché le proprietà sono implementate come metodi molto sottili, è possibile impostare punti di interruzione sulla lettura e scrittura dei loro valori. Questo dà loro un vantaggio sui campi.


2
Dieci anni dopo, i punti di interruzione dei dati sono qui, almeno per .NET Core :)
Luaan,

72

Il passaggio da un campo a una proprietà comporta la rottura del contratto (ad es. Richiede la ricompilazione di tutto il codice di riferimento). Quindi, quando hai un punto di interazione con altre classi - qualsiasi membro pubblico (e generalmente protetto), vuoi pianificare una crescita futura. Fallo utilizzando sempre le proprietà.

Oggi non è nulla per renderlo un'auto-proprietà e 3 mesi dopo capisci che vuoi renderlo carico di energia e metti un segno di spunta nel getter. Se hai usato un campo, questo è un cambiamento di ricompilazione nel migliore dei casi e impossibile nel peggiore dei casi, a seconda di chi e cos'altro dipende dai tuoi assiemi.


9
Mi è piaciuta questa risposta perché non usa le parole "riflesso", "interfaccia" o "ignora". (

65

Solo perché nessuno lo ha menzionato: non è possibile definire i campi sulle interfacce. Quindi, se devi implementare un'interfaccia specifica che definisce le proprietà, le proprietà automatiche a volte sono davvero una bella funzionalità.


1
Direi che se hai bisogno di un'interfaccia che definisce le proprietà, dovrebbe essere una classe astratta. Solo perché c # ti consente di definire le proprietà nelle interfacce, non significa che dovresti usarle. È un cattivo design.
Odys,

8
@odyodyodys - Non sono sicuro di essere d'accordo sul fatto che si tratti di un cattivo design. Per favore, spiega la tua logica?
Zaid Masud,

4
@odyodyodys Concordo con zooone9243: Imp, dal punto di vista del design, non c'è differenza tra dichiarare una proprietà e dichiarare una coppia getter / setter (che è pratica comune per le interfacce).
MartinStettner,

22
@ zooone9243, + MartinStettner: 6 mesi fa, ho imparato molto da allora. Lo sto riprendendo :)
Odys,

47

Un'enorme differenza che viene spesso trascurata e non è menzionata in nessun'altra risposta: ignorare . Puoi dichiarare le proprietà virtuali e sovrascriverle mentre non puoi fare lo stesso per i campi dei membri pubblici.


10

Riguarda il controllo delle versioni e la stabilità dell'API. Non c'è alcuna differenza, nella versione 1 - ma in seguito, se decidi di renderlo una proprietà con un qualche tipo di controllo degli errori nella versione 2, non devi cambiare la tua API - nessuna modifica del codice, ovunque, tranne che la definizione della proprietà.


10

Un altro vantaggio delle proprietà implementate automaticamente sui campi pubblici è che puoi rendere gli accessi impostati privati ​​o protetti, fornendo alla classe di oggetti in cui è stato definito un controllo migliore rispetto a quello dei campi pubblici.


8

Non c'è niente di sbagliato nel creare un campo public. Ma ricorda che creare getter/settercon i privatecampi non è incapsulamento. IMO, se non ti interessano altre funzionalità di a Property, potresti anche farcela public.


1

Se in seguito decidi di verificare che il titolo sia univoco, confrontandolo con una raccolta o un database, puoi farlo nella proprietà senza modificare alcun codice che dipende da esso.

Se utilizzi solo un attributo pubblico, avrai meno flessibilità.

La maggiore flessibilità senza rompere il contratto è la cosa più importante per me nell'uso delle proprietà e, fino a quando non ho effettivamente bisogno della flessibilità, l'auto-generazione ha più senso.


0

Una cosa che trovo molto utile oltre a tutto il codice e i motivi del test è che se si tratta di una proprietà contro un campo è che l'IDE di Visual Studio mostra i riferimenti per una proprietà ma non un campo.


0

Il mio pov dopo ha fatto alcune ricerche

  1. Convalida.
  2. Consenti l'override dell'accessor per modificare il comportamento di una proprietà.
  3. Scopo del debug. Saremo in grado di sapere quando e cosa cambia la proprietà impostando un breakpoint nell'accessor.
  4. Possiamo avere solo un set di campi. Ad esempio, public set () e private get (). Questo non è possibile con il campo pubblico.

Ci dà davvero più possibilità ed estensibilità.

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.