Variabile privata vs proprietà?

41

Quando si imposta un valore su una variabile all'interno di una classe la maggior parte delle volte vengono presentate due opzioni:

private string myValue;
public string MyValue
{
   get { return myValue; }
   set { myValue = value; }
}

Esiste una convenzione che determina come dovremmo assegnare valori alle variabili all'interno delle nostre classi? Per esempio se ho un metodo all'interno della stessa classe dovrei assegnarlo usando la proprietà o usando la variabile privata. L'ho visto fare in entrambi i modi, quindi mi chiedevo se questa è una scelta o la performance è un fattore (minore, probabilmente).

    
posta Edward 02.02.2012 - 18:21
fonte

8 risposte

22

Vorrei fare un ulteriore passo avanti e portarlo a 3 casi. Anche se ci sono delle variazioni su ognuna, queste sono le regole che uso la maggior parte delle volte durante la programmazione in C #.

Nel caso 2 e 3, vai sempre all'accessorio della proprietà (non alla variabile di campo). E nel caso 1, sei salvato anche dal dover fare questa scelta.

1.) Proprietà immutabile (passata al costruttore o creata in fase di costruzione). In questo caso, utilizzo una variabile di campo, con una proprietà di sola lettura. Scelgo questo su un setter privato, dal momento che un setter privato non garantisce l'immutabilità.

public class Abc
{ 
  private readonly int foo;

  public Abc(int fooToUse){
    foo = fooToUse;
  }

  public int Foo { get{ return foo; } }
}

2.) Variabile POCO. Una variabile semplice che può essere / impostata in qualsiasi ambito pubblico / privato. In questo caso, utilizzerei solo una proprietà automatica.

public class Abc
{ 
  public int Foo {get; set;}
}

3.) Proprietà di associazione ViewModel. Per le classi che supportano INotifyPropertyChanged, penso che tu abbia bisogno di una variabile di backinging privata.

public class Abc : INotifyPropertyChanged
{
  private int foo;

  public int Foo
  {
    get { return foo; }
    set { foo = value;  OnPropertyChanged("foo"); }
  }
}
    
risposta data 02.02.2012 - 19:21
fonte
18

In generale, direi di assegnare al campo nel costruttore e usare la proprietà ovunque. In questo modo, se qualcuno aggiunge funzionalità alla proprietà, non ti mancherà da nessuna parte.

Certamente non è un fattore di prestazioni. L'ottimizzatore inline un semplice get o set per te e il codice MSIL finale sarà probabilmente identico.

    
risposta data 02.02.2012 - 18:32
fonte
4

Dipende.

Per prima cosa dovresti preferire le proprietà automatiche quando possibile:

public string MyValue {get;set;}

In secondo luogo, l'approccio migliore sarebbe probabilmente quello di utilizzare le proprietà, se si dispone di una logica in questo caso, è probabile che lo si passi da soli, soprattutto se tale logica è la sincronizzazione dei thread.

Ma dovresti anche considerare che potrebbe ostacolare le tue prestazioni (un po '), se stai sincronizzando in modo errato puoi metterti in una situazione di stallo, e talvolta il percorso corretto è aggirare la logica nella proprietà.

    
risposta data 02.02.2012 - 18:34
fonte
3

Bene, l'approccio straight-to-the-point sarebbe semplicemente assegnarlo alla variabile stessa, dato che sei all'interno di un metodo di classe e comunque controlli il comportamento della classe.

Ma il punto fondamentale delle proprietà è che astraggono la variabile. Mentre una proprietà così semplice come nel tuo esempio non ha assolutamente alcun effetto su una semplice variabile membro pubblica, le proprietà solitamente fanno (o dovrebbero fare) cose aggiuntive all'interno dei loro getter e setter. E se vuoi che queste cose vengano eseguite automaticamente quando si modifica la proprietà all'interno della classe, è ovviamente più pulito lavorare sulla proprietà anziché sulla variabile per non dover modificare ogni assegnazione di variabile quando cambia il comportamento di impostazione delle proprietà.

Devi solo ragionare concettualmente. La proprietà è in realtà un handle per accedere ad alcuni stati interni dell'oggetto, che possono essere costituiti da più di una variabile membro. Quindi devi chiederti se vuoi cambiare solo lo stato interno sottostante (o solo parte di esso) o la proprietà astratta che rappresenta questo stato nel suo insieme, e la maggior parte delle volte è proprio quest'ultimo dato che di solito vuoi che il tuo oggetto abbia sempre uno stato coerente.

    
risposta data 02.02.2012 - 18:38
fonte
2

Se c'è qualche possibilità che l'implementazione get / set di queste proprietà cambierà qualche volta più tardi (ad esempio, vuoi aumentare un evento quando chiami set , o aggiungerai qualche meccanismo di valutazione pigro in seguito alla tua funzione get ), quindi potrebbe essere una buona idea che il codice all'interno della classe utilizzi la proprietà in quasi tutti i casi tranne che nei casi più rari in cui esplicitamente non desideri quegli eventi o pigri meccanismi di valutazione da utilizzare.

In ogni caso, qualunque cosa tu faccia, ci sono buone probabilità che quando cambi l'implementazione della proprietà in un secondo momento, dovrai controllare tutti i posti della tua classe che accedono a quelle proprietà per verificare se davvero la proprietà deve essere accesso o utilizzare la variabile privata.

    
risposta data 02.02.2012 - 18:32
fonte
2

Uso sempre la proprietà pubblica.

Spesso una logica che deve sempre essere eseguita quando la proprietà è impostata viene aggiunta al metodo set di una proprietà, e impostando il campo privato invece il setter pubblico ignorerà qualsiasi logica presente.

Hai un commento su MVVM che porta a questa domanda e ritengo che ciò sia ancora più importante quando si lavora con MVVM. Molti oggetti sollevano una notifica di PropertyChange al setter e altri oggetti possono iscriversi a questo evento per eseguire un'azione quando cambiano proprietà specifiche. Se imposti la variabile privata, queste azioni non verranno mai eseguite a meno che non venga generato manualmente anche l'evento PropertyChanged .

    
risposta data 02.02.2012 - 19:53
fonte
1

Generalmente, sta a te decidere cosa fare con una proprietà e il suo campo di supporto quando ottieni / imposta.

Molto spesso, solo per essere coerenti con il codice, è necessario utilizzare i metodi di accesso pubblici ovunque siano disponibili e appropriati. Ciò consente di effettuare il refactoring con un minimo cambiamento di codice; se il metodo che esegue questa impostazione deve essere rimosso dalla classe e messo altrove dove il campo di supporto non è più disponibile (come una classe base), a chi importa? Stai usando qualcosa che è disponibile ovunque la classe stessa faccia il lavoro. Il campo di supporto, nella maggior parte dei casi, è un dettaglio di implementazione; nessuno al di fuori della tua classe dovrebbe sapere che esiste.

La situazione principale a cui posso pensare quando si deve usare il backing field e NON la proprietà accessor è quando l'accessor ha una logica aggiuntiva (validazione o aggiornamento di altre informazioni di stato nella classe) che non si desidera eseguire. La popolazione iniziale di un oggetto è un esempio; potresti avere una classe che usa due valori di proprietà per calcolare un terzo, che è anche memorizzato in un campo di supporto (per ragioni di persistenza). Quando si inizializza una nuova copia di quell'oggetto dati dati dal DB, gli accessor di proprietà che ricalcolano ciascuno il terzo valore potrebbero lamentarsi se l'altro valore richiesto non è impostato. Utilizzando i campi di supporto per impostare i valori iniziali di queste due (o tre) proprietà, si ignora la logica di validazione / calcolo finché l'istanza non si trova in uno stato abbastanza coerente affinché la logica funzioni normalmente.

    
risposta data 02.02.2012 - 20:35
fonte
0

Usa sempre quello che ha senso. Sì, lo so che sembra abbastanza fasullo fino al punto di non rispondere.

Il punto delle proprietà è fornire un'interfaccia attraverso cui è possibile accedere in sicurezza a un modello di dati. Per la maggior parte delle situazioni, si desidera sempre accedere in sicurezza al modello di dati tramite tale interfaccia, ad esempio:

public Foo Bar
{
  get { return _bar; }
  set { _bar = doSomethingTo(value); }
}

Ma in altre situazioni, potresti semplicemente utilizzare una proprietà come vista di un modello di dati:

public Double SomeAngleDegrees
{
  get { return SomeAngleRadians * 180 / PI; }
  set { SomeAngleRadians = value * PI / 180; }
}

Se ha senso usare la forma radianti di SomeAngle , quindi usarlo con tutti i mezzi.

Alla fine, assicurati di bere il tuo kool-aid. La tua API pubblica dovrebbe essere abbastanza flessibile da funzionare internamente.

    
risposta data 03.02.2012 - 02:45
fonte

Leggi altre domande sui tag