Ci sono dei motivi per usare le proprietà private in C #?


246

Ho appena realizzato che il costrutto della proprietà C # può essere utilizzato anche con un modificatore di accesso privato :

private string Password { get; set; }

Anche se questo è tecnicamente interessante, non riesco a immaginare quando lo userei dal momento che un campo privato prevede anche meno cerimonie :

private string _password;

e non riesco a immaginare quando avrei mai bisogno di essere in grado di ottenere internamente ma non impostare o impostare ma non ottenere un campo privato:

private string Password { get; }

o

private string Password { set; }

ma forse c'è un caso d'uso con classi nidificate / ereditate o forse in cui un get / set potrebbe contenere la logica invece di restituire semplicemente il valore della proprietà, anche se tenderei a mantenere le proprietà rigorosamente semplici e permettere ai metodi espliciti di fare qualsiasi logica, es GetEncodedPassword().

Qualcuno usa le proprietà private in C # per qualche motivo o è solo uno di quei costrutti tecnicamente possibili, ma raramente usati nel codice attuale?

appendice

Belle risposte, leggendole ho abbattuto questi usi per proprietà private:

  • quando i campi privati ​​devono essere caricati pigramente
  • quando i campi privati ​​richiedono logica aggiuntiva o sono valori calcolati
  • poiché i campi privati ​​possono essere difficili da eseguire il debug
  • per "presentare un contratto a te stesso"
  • per convertire / semplificare internamente una proprietà esposta come parte della serializzazione
  • a capo di variabili globali da utilizzare all'interno della tua classe

La tecnica incoraggiata dalle proprietà private è l'autoincapsulamento autoincapsulamento
LBushkin

Risposte:


212

Li uso se ho bisogno di memorizzare un valore nella cache e voglio caricarlo lentamente.

private string _password;
private string Password
{
    get
    {
        if (_password == null)
        {
            _password = CallExpensiveOperation();
        }

        return _password;
    }
}

42
un bel modello comune per questo èreturn _password ?? (_password = CallExpensiveOperation());
Marc

1
@EvAlex Lazy <T> potrebbe essere preferibile se puoi usarlo. Ma può usare solo roba statica, quindi non puoi accedere a metodi (non statici) o ad altri membri. A proposito, preferisco la sintassi a linea singola return _password ?? (_password = CallExpensiveOperation());da un po '. O in realtà Resharper lo preferisce :).
Bart,

4
@Marc dal C # 6 non devi nemmeno scrivere get e return. private string Password => _password ?? (_password = CallExpensiveOperation());
Otto Abnormalverbraucher,

1
Con C # 8 è ancora più breve:private string Password => _password ??= CallExpensiveOperation();
Dave M

2
@Bas Questo non è un caricamento lento perché CallExpensiveOperation();viene chiamato durante la costruzione / inizializzazione dell'oggetto contenitore e non al primo accesso alla proprietà.
Stefan Podskubka,

142

L'uso principale di questo nel mio codice è l'inizializzazione lazy, come altri hanno già detto.

Un altro motivo per le proprietà private sui campi è che le proprietà private sono molto, molto più facili da eseguire il debug dei campi privati. Spesso desidero sapere cose come "questo campo viene impostato in modo imprevisto; chi è il primo chiamante che imposta questo campo?" ed è molto più semplice se puoi semplicemente mettere un breakpoint sul setter e premere go. Puoi inserire la registrazione lì. Puoi inserire le metriche delle prestazioni. È possibile inserire controlli di coerenza eseguiti nella build di debug.

Fondamentalmente, si riduce a: il codice è molto più potente dei dati . Qualsiasi tecnica che mi permetta di scrivere il codice di cui ho bisogno è buona. I campi non ti consentono di scrivere codice al loro interno, lo fanno le proprietà.


5
"Il codice è molto più potente dei dati" che dici? Googling restituisce riferimenti che puntano a te. Voglio solo sapere in modo da poterlo citare correttamente quando ne ho bisogno.
Joan Venge,

24
@Joan: non lo so. O l'ho inventato, o ho sentito qualcun altro dirlo e ho pensato "wow, dovrei rubarlo del tutto, e poi dimenticare tutto da chi l'ho rubato".
Eric Lippert,

1
+ CodeLens ti dice dove si fa riferimento alla proprietà
UuDdLrLrSs

43

forse c'è un caso d'uso con classi nidificate / ereditate o forse dove un get / set potrebbe contenere la logica invece di restituire semplicemente il valore della proprietà

Personalmente lo uso anche quando non ho bisogno di logica sul getter o sul setter di una proprietà. L'uso di una proprietà, anche privata, aiuta a rendere il codice a prova di futuro in modo da poter aggiungere la logica a un getter in un secondo momento, se necessario.

Se ritengo che una proprietà possa eventualmente richiedere una logica aggiuntiva, a volte la avvolgo in una proprietà privata invece di utilizzare un campo, solo per non dover modificare il mio codice in un secondo momento.


In un caso semi-correlato (anche se diverso dalla tua domanda), utilizzo molto frequentemente i setter privati ​​su proprietà pubbliche:

public string Password 
{
    get; 
    private set;
}

Questo ti dà un pubblico migliore, ma mantiene il setter privato.


+1 ha senso: "Se ritengo che una proprietà possa eventualmente richiedere una logica aggiuntiva, a volte la avvolgo in una proprietà privata invece di utilizzare un campo, solo per non dover modificare il mio codice in seguito".
Edward Tanguay,

7
setter privati ​​<3
Earlz,

20

Un buon utilizzo per le proprietà private get only sono i valori calcolati. Diverse volte ho avuto proprietà che sono di sola lettura private e faccio solo un calcolo su altri campi nel mio tipo. Non è degno di un metodo e non è interessante per altre classi, quindi è di proprietà privata.


20

L'inizializzazione lenta è un punto in cui possono essere ordinati, ad es

private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */);

private MyType MyType { get { return this.mytype.Value; } }

// In C#6, you replace the last line with: private MyType MyType => myType.Value;

Quindi puoi scrivere: this.MyTypeovunque piuttosto che this.mytype.Valueincapsulare il fatto che sia pigramente istanziato in un unico posto.

Una cosa che è un peccato è che C # non supporti l'ambito del campo di backup sulla proprietà (cioè dichiarandolo all'interno della definizione della proprietà) per nasconderlo completamente e garantire che sia possibile accedervi solo tramite la proprietà.


2
Concordato che avrebbe avuto l'aspetto di scoping lì.
Chris Marisic,

5
Uso frequentemente questa stessa tecnica e ho anche desiderato che un campo potesse essere impostato su un corpo di codice. È una bella funzionalità ma a bassa priorità.
Eric Lippert,

5
L'ambito di @Eric Lippert field-declarationcon il accessor-declarationsnumero uno nella mia lista dei desideri di C # è da molto tempo. Se riuscissi a farlo progettare e implementare in una (futura) versione futura, allora ti preparerò una torta.
Jeffrey L Whitledge,

13

L'unico uso che mi viene in mente

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}

+1 per l'utile classe di proprietà che sono calcolate da altre variabili private
Daren Thomas,

2
Perché non usare un metodo privatoprivate bool IsPasswordSet() { return !String.IsNullOrEmpty(_password); }
Roman

10

Proprietà e campi non sono uno a uno. Una proprietà riguarda l'interfaccia di una classe (sia che si tratti della sua interfaccia pubblica o interna), mentre un campo riguarda l'implementazione della classe. Le proprietà non dovrebbero essere viste come un modo per esporre solo i campi, dovrebbero essere viste come un modo per esporre l'intento e lo scopo della classe.

Proprio come usi le proprietà per presentare un contratto ai tuoi consumatori su ciò che costituisce la tua classe, puoi anche presentare un contratto a te stesso per ragioni molto simili. Quindi sì, uso le proprietà private quando ha senso. A volte una proprietà privata può nascondere i dettagli dell'implementazione come il caricamento lento, il fatto che una proprietà sia realmente un conglomerato di diversi campi e aspetti o che una proprietà debba essere virtualmente istanziata ad ogni chiamata (pensa DateTime.Now). Ci sono sicuramente momenti in cui ha senso imporlo anche su te stesso nel backend della classe.


+1: "puoi anche presentare un contratto a te stesso per ragioni molto simili" ha senso
Edward Tanguay,

8

Li uso in serializzazione, con cose come DataContractSerializero protobuf-net che supportano questo utilizzo ( XmlSerializerno). È utile se è necessario semplificare un oggetto come parte della serializzazione:

public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
    get { return SomeProp.ToInt32(); }
    set { SomeProp = SomeComplexType.FromInt32(value); }
}

6

Una cosa che faccio sempre è memorizzare variabili / cache "globali" HttpContext.Current

private static string SomeValue{
  get{
    if(HttpContext.Current.Items["MyClass:SomeValue"]==null){
      HttpContext.Current.Items["MyClass:SomeValue"]="";
    }
    return HttpContext.Current.Items["MyClass:SomeValue"];
  }
  set{
    HttpContext.Current.Items["MyClass:SomeValue"]=value;
  }
}

5

Li uso ogni tanto. Possono semplificare il debug delle cose quando puoi facilmente inserire un punto di interruzione nella proprietà o puoi aggiungere un'istruzione di registrazione ecc.

Può anche essere utile se in seguito è necessario modificare il tipo di dati in qualche modo o se è necessario utilizzare la riflessione.


Idem; se c'è una logica in un get / set, a volte potrei usare una proprietà privata o protetta. Dipende generalmente da quanta logica: logica semplice farò nella proprietà, molta logica di solito userò una funzione ausiliaria. Qualunque cosa renda il codice più gestibile.
TechNeilogy,

5

Uso le proprietà private per ridurre il codice per accedere alle proprietà secondarie che spesso usano.

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }

È utile se ci sono molte proprietà secondarie.


2

È una pratica comune modificare i membri solo con metodi get / set, anche privati. Ora, la logica alla base è che sai che il tuo get / set si comporta sempre in un modo particolare (ad esempio, sparando eventi) che non sembra avere senso dal momento che quelli non saranno inclusi nello schema delle proprietà ... ma le vecchie abitudini sono dure a morire.


2

Ha perfettamente senso quando c'è una logica associata al set di proprietà o get (pensa all'inizializzazione lazy) e la proprietà viene utilizzata in alcuni punti della classe.

Se è solo un campo protetto? Nulla viene in mente come una buona ragione.


2

So che questa domanda è molto vecchia ma le informazioni di seguito non erano in nessuna delle risposte attuali.

Non riesco a immaginare quando avrei mai dovuto essere in grado di ottenere internamente ma non impostare

Se stai iniettando le tue dipendenze, potresti voler avere un Getter su una proprietà e non un setter in quanto ciò denoterebbe una proprietà di sola lettura. In altre parole, la proprietà può essere impostata solo nel costruttore e non può essere modificata da nessun altro codice all'interno della classe.

Inoltre Visual Studio Professional fornirà informazioni su una proprietà e non su un campo, semplificando la visualizzazione del campo utilizzato.

PorpField


1

Bene, come nessuno ha detto, puoi usarlo per convalidare i dati o per bloccare le variabili.

  • Validazione

    string _password;
    string Password
    {
        get { return _password; }
        set
        {
            // Validation logic.
            if (value.Length < 8)
            {
                throw new Exception("Password too short!");
            }
    
            _password = value;
        }
    }
  • Locking

    object _lock = new object();
    object _lockedReference;
    object LockedReference
    { 
        get
        {
            lock (_lock)
            {
                return _lockedReference;
            }
        }
        set
        {
            lock (_lock)
            {
                _lockedReference = value;
            }
        }
    }

    Nota: quando si blocca un riferimento, non si blocca l'accesso ai membri dell'oggetto a cui si fa riferimento.

Riferimento pigro: quando si carica pigro potresti finire con la necessità di farlo asincrono per il quale al giorno d'oggi c'è AsyncLazy . Se utilizzi versioni precedenti rispetto a Visual Studio SDK 2015 o non lo usi, puoi anche utilizzare AsyncEx di AsyncEx .


0

Alcuni usi più esotici di campi espliciti includono:

  • devi usare refo outcon il valore, forse perché è unInterlocked contatore
  • esso è destinato a rappresentare la layout fondamentale ad esempio su unstruct layout esplicito (forse per mappare a un dump C ++, ounsafe codice)
  • storicamente il tipo è stato usato con BinaryFormatterla gestione automatica del campo (il passaggio ad auto-oggetti cambia i nomi e quindi interrompe il serializzatore)
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.