Dovresti creare proprietà private?


19
private string mWhatever;

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = value;
    }
}

Ho visto alcune persone che hanno proprietà per ogni singolo membro, private o no ... ha senso? Potrei vederlo avere senso nell'1% dei casi a volte quando si desidera controllare l'accesso al membro all'interno della classe che lo contiene perché se non si utilizzassero le proprietà per ogni membro, si verificherebbero incongruenze e verificare se il membro ha un accesso o meno (dal momento che hai accesso a entrambi nell'ambito della classe).

Risposte:


17

Risposta breve: , quando è necessario. Altrimenti, usa un getter e setter di proprietà implementati automaticamenteprivate string Whatever { get; set;}

  • È molto utile quando si utilizza un approccio di dominio ravvicinato
  • È anche utile quando si deve controllare una logica specifica quando si imposta il valore

Ecco una descrizione completa di quando useresti setter privati: utilizzo della proprietà C # .


È anche molto semplice rendere pubblica la proprietà in seguito, se necessario.
Tom Pickles,

4
Che cos'è un approccio di dominio stretto ?
Trisped il

1
Mi riferivo a un setter privato in una proprietà della classe. Dovrebbe impedire l'accesso diretto per impostare il valore dall'oggetto e facilitare un controllo logico prima di impostare il valore.
Yusubov,

avere variabili private con setter / getter pubblici (anche se sono solo ingenui) ha anche il vantaggio che se il tuo codice viene compilato in una libreria, la firma rimarrà invariata se sostituisci setter / getter ingenui con quelli che hanno side- effetto ecc. ma se si utilizza invece una semplice variabile pubblica, la firma della libreria cambierebbe se la si cambiasse in un setter / getter privato / non ingenuo. .. il che significherebbe che se la tua libreria fosse cambiata in quel modo, i consumatori della tua libreria avrebbero dovuto ricompilarsi.
orion elenzil,

12

Alcune buone risposte già qui, ma penso che la maggior parte di loro manchi un punto della tua domanda:

Ho visto alcune persone che hanno proprietà per ogni singolo membro, private o no ... ha senso?

Penso che questo sia raramente necessario in anticipo, per ogni singolo membro . Iniziare con

 private string Whatever;

Quando in seguito arrivate a un punto in cui è necessario l' incapsulamento o un punto di interruzione condizionale per questo membro specifico, è ancora possibile sostituirlo con una proprietà con lo stesso nome, nella maggior parte dei casi senza modificare il codice che utilizza Whatever. Ma attenzione, ci sono sottili differenze, vedi la risposta di Brian Rasmussen in questo post SO (link fornito anche da Emmad Kareem, +1).


+1, inoltre, hai ragione, la maggior parte delle risposte ha mancato i punti di domanda originali, siamo ragazzi IT tipici :)
NoChance

Il refactoring di un campo a una proprietà dopo il fatto è un incubo; richiedendo di ricompilare tutti i consumatori. La modifica di una proprietà automatica per contenere la logica personalizzata è un gioco da ragazzi. Se c'è anche una leggera possibilità che il codice veda il refactor, sarà molto meno lavoro se usi le proprietà sin dall'inizio.
Dan

@Dan: nella maggior parte dei progetti ho visto che lo sforzo è abbastanza lo stesso, devi ricompilare in entrambi i casi. Tuttavia, penso che tu abbia ragione nel dire che l'uso delle proprietà, in particolare le proprietà automatiche, può aiutare ad evitare alcuni problemi di sottotile con la riflessione o l'uso di variabili membro nei parametri "out".
Doc Brown

@DocBrown In ogni caso, sicuramente non è un'affermazione generale. Ci sono molte ragioni per renderlo semplice e usare un campo. Se riesci a prevedere un refattore, tuttavia, vale la pena considerare anche i problemi sottili.
Dan

7

Uno dei maggiori vantaggi di questo approccio è il controllo su quando cambiano le variabili .

Considera quanto segue.
Stai eseguendo il debug di un grande progetto. Un certo metodo genera un'eccezione. Si imposta un punto di interruzione e si rivela che una determinata variabile membro ha un valore errato. Supponiamo che il tuo codice si basi molto su questa variabile e trovi centinaia di usi di scrittura ( scenario Spaghetti ). Quindi non puoi capire a quale di questi usi è stato assegnato un valore negativo.
Se il codice è multithread, il debug può diventare un vero incubo.

Con la proprietà, è possibile impostare un punto di interruzione in un setter . Combinato con una condizione, può essere inchiodato in una sola corsa.

VC ++ ha punti di interruzione dei dati , ma è disponibile solo per codice non gestito.


1

Se non si utilizza una proprietà, l'unica altra opzione è utilizzare un campo per archiviare dati variabili. Proprietà e campi presentano differenze significative. La maggior parte di queste differenze si trova Fields vs. Properties . Ti suggerisco di studiare le differenze e poi fare la tua scelta in base alle esigenze della tua applicazione. Tuttavia, tenere presente che l'utilizzo dei campi anziché delle proprietà non è la pratica OO comune a causa della loro natura e carenza.


1

Le proprietà private possono essere molto utili per incapsulare il comportamento delle cose interne alla tua classe. Solo perché sono privati ​​non significa che non dovresti approfittare dello zucchero sintattico che le proprietà ti danno.


L'esempio fornito è tuttavia scarso. Getter e setter di proprietà della caldaia come questa sono quasi sempre una cattiva idea. Se si utilizza C # 3.0 o versione successiva, le proprietà automatiche sono un'idea molto migliore:

private string Whatever { get; set; };

Questo è più breve, più pulito e molto più leggibile. In effetti è appena più lungo della semplice dichiarazione della variabile di supporto.

Ancora più importante, tuttavia, le proprietà automatiche possono essere convertite in proprietà complete in qualsiasi momento senza modificare la semantica del resto del programma! Pertanto, se è necessario aggiungere la convalida o la gestione degli errori, è possibile farlo facilmente.


Così com'è, ho sempre pensato che fosse un peccato non poter avere una proprietà di sola lettura, imporre solo la possibilità di scrivere sul valore nel costruttore ( preferisco i tipi immutabili ) ma questo è stato aggiunto in C # 6.0 come "Inizializzatori proprietà automatica", che consente di:

private string Whatever { get; } = ...;

o

private string Whatever { get; };

insieme a

    Whatever = ...;

nel costruttore.


0

Non è assolutamente necessario farlo per le proprietà private, ma consente di modificare il modo in cui la proprietà ottiene / imposta il valore sottostante senza cambiare la modalità di accesso.

Ad esempio, modificando come viene impostato il valore sottostante:

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = string.IsNullOrEmpty(value) ? string.Empty : value;
    }
}

0

si

Personalmente lo uso come meccanismo di memorizzazione nella cache e potremmo chiamarlo cache a livello di proprietà .

private List<User> users;
private List<User> Users
{
    get
    {
        if(users == null) users = new UserManager().GetUsers();
        return users;
    }
}

Ora in altri posti all'interno della mia classe, uso la Usersproprietà anziché il userscampo.

Un'altra situazione possibile potrebbe essere quando si desidera implementare una logica su un campo, ma in modo centralizzato in una classe. In questo modo è possibile sia creare un GetFoo()metodo, sia una Fooproprietà per il foocampo.

private string foo;
private string Foo
{
    get
    {
        return "Mr. " + foo;
    }
}

0

Qualcos'altro da considerare:

Le proprietà effettive sono un dettaglio di implementazione. Uno degli obiettivi di OOP è cercare di ridurre al minimo l'esposizione dei dettagli di implementazione laddove possibile.

La ragione di ciò è che se nascondi le proprietà e le esponi solo attraverso getter e setter, hai un controllo molto maggiore. Ad esempio, il tuo getter può convalidare il suo input e impedire che la proprietà venga impostata su uno stato non valido. Se la possibilità di modificare il valore è critica nel tempo, anche il setter può proteggerlo. Il getter, se ottenere il valore effettivo sia costoso per qualsiasi motivo, può eseguire l'inizializzazione e / o la memorizzazione nella cache lazy.

Avere esposti getter e setter e nascondere le proprietà significa che a volte non è necessaria alcuna proprietà. Il tuo getter può calcolare il valore al momento dell'invocazione o delegare l'attività da qualche altra parte o qualsiasi cosa gli permetta di soddisfare le sue specifiche. La cosa importante della tua classe sono le informazioni a cui puoi accedere da essa, non il modo in cui tali informazioni sono rappresentate internamente.

Naturalmente, se non ci sono conseguenze negative su qualcosa che al di fuori della classe sia in grado di accedere direttamente a una proprietà, allora dovresti semplicemente renderlo pubblico. Tuttavia, nella mia esperienza, tali casi sono relativamente pochi e lontani tra loro.


0

So che questa è una vecchia domanda e tutto ciò che @Yusubov ha detto è corretto, ma per quanto riguarda il suo secondo punto elenco sulla logica specifica nel setter, e poiché non ho visto nessuno menzionarlo in modo specifico, un esempio perfetto sarebbe quando la tua classe implementa l' INotifyPropertyChangedinterfaccia.

Questo è usato una tonnellata in WCF e Silverlight che ti permette di sapere quando una specifica proprietà è cambiata tramite la logica nel suo setter come nella classe seguente:

public class Settings : INotifyPropertyChanged
{
    public Settings() 
    { 
        this.CountryField = String.Empty; 
    }

    private string CountryField;
    public string Country
    {
        get { return this.CountryField; }
        set
        {
            if (Object.ReferenceEquals(this.CountryField, value)) { return; }

            this.CountryField = value;
            this.RaisePropertyChanged("Country");
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
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.