Domanda

Vedo un sacco di codice di esempio per le classi C # che fa questo:

public class Point {
    public int x { get; set; }
    public int y { get; set; }
}

O, nel vecchio codice, lo stesso con un valore di supporto privato esplicito e senza le nuove proprietà implementate automaticamente:

public class Point {
    private int _x;
    private int _y;

    public int x {
        get { return _x; }
        set { _x = value; }
    }

    public int y {
        get { return _y; }
        set { _y = value; }
    }
}

La mia domanda è: perché. C'è qualche differenza funzionale tra fare quanto sopra e semplicemente rendere questi membri campi pubblici, come sotto?

public class Point {
    public int x;
    public int y;
}

Per essere chiari, comprendo il valore di getter e setter quando è necessario fare una traduzione dei dati sottostanti. Ma nei casi in cui stai solo passando i valori, sembra inutilmente prolisso.

È stato utile?

Soluzione

Tendo ad essere d'accordo (che sembra inutilmente prolisso), anche se questo è stato un problema che il nostro team non ha ancora risolto e quindi i nostri standard di codifica insistono ancora su proprietà verbose per tutte le classi.

Jeff Atwood ha affrontato questo problema alcuni anni fa. Il punto più importante che ha notato retrospettivamente è che il passaggio da un campo a una proprietà è un rottura del cambiamento nel tuo codice; tutto ciò che la consuma deve essere ricompilato per funzionare con la nuova interfaccia di classe, quindi se qualcosa al di fuori del tuo controllo consuma la tua classe potresti avere problemi.

Altri suggerimenti

È anche molto più semplice cambiarlo in un secondo momento:

public int x { get; private set; }

Incapsula l'impostazione e l'accesso di quei membri. Se da qualche tempo uno sviluppatore del codice deve modificare la logica quando si accede o imposta un membro, è possibile farlo senza modificare il contratto della classe.

L'idea è che anche se la struttura di dati sottostante deve cambiare, l'interfaccia pubblica alla classe non dovrà essere cambiata.

C # può trattare proprietà e variabili in modo diverso a volte. Ad esempio, non puoi passare le proprietà come parametri ref o out . Quindi, se è necessario modificare la struttura dei dati per qualche motivo e si utilizzavano variabili pubbliche e ora è necessario utilizzare le proprietà, è necessario modificare l'interfaccia e ora il codice che accede alla proprietà x potrebbe non essere più compilato come quando era variabile x:

Point pt = new Point();
if(Int32.TryParse(userInput, out pt.x))
{
     Console.WriteLine("x = {0}", pt.x);
     Console.WriteLine("x must be a public variable! Otherwise, this won't compile.");
}

L'uso delle proprietà fin dall'inizio evita questo e puoi sentirti libero di modificare l'implementazione sottostante tanto quanto è necessario senza rompere il codice client.

Setter e Getter ti consentono di aggiungere un ulteriore livello di astrazione e in OOP puro dovresti sempre accedere agli oggetti tramite l'interfaccia che stanno fornendo al mondo esterno ...

Considera questo codice, che ti salverà in asp.net e che non sarebbe possibile senza il livello di astrazione fornito da setter e getter:

class SomeControl
{

private string _SomeProperty  ;
public string SomeProperty 
{
  if ( _SomeProperty == null ) 
   return (string)Session [ "SomeProperty" ] ;
 else 
   return _SomeProperty ; 
}
}

Poiché i getter implementati automaticamente prendono lo stesso nome per la proprietà e le variabili di archiviazione private effettive. Come puoi cambiarlo in futuro? Penso che il punto detto sia che usa l'implementazione automatica invece del campo in modo da poterlo modificare in futuro se nel caso in cui hai bisogno di aggiungere logica a getter e setter.

Ad esempio:

public string x { get; set; }

e per esempio usi già x molte volte e non vuoi rompere il tuo codice.

Come si modifica il setter del getter automatico ... ad esempio, per il setter si consente solo l'impostazione di un formato di numero di telefono valido ... come si cambia il codice in modo da cambiare solo la classe?

La mia idea è aggiungere una nuova variabile privata e aggiungere lo stesso x getter e setter.

private string _x;

public string x { 
    get {return x}; 
    set {
        if (Datetime.TryParse(value)) {
            _x = value;
        }
    }; 
}

È questo che intendi rendendolo flessibile?

Da considerare anche l'effetto della modifica ai membri pubblici quando si tratta di associazione e serializzazione. Entrambi spesso si basano su proprietà pubbliche per recuperare e impostare valori.

Inoltre, puoi inserire punti di interruzione su getter e setter, ma non sui campi.

AFAIK l'interfaccia CIL generata è diversa. Se cambi un membro pubblico in una proprietà, stai cambiando la sua interfaccia pubblica e devi ricostruire ogni file che utilizza quella classe. Ciò non è necessario se si modifica solo l'implementazione di getter e setter.

Forse solo rendendo pubblici i campi potresti portarti a un Anemic Domain Model .

Cordiali saluti

Vale anche la pena notare che non è possibile rendere le proprietà automatiche in sola lettura e non è possibile inizializzarle in linea. Entrambe sono cose che vorrei vedere in una versione futura di .NET, ma credo che non si possa fare né in .NET 4.0.

Le uniche volte in cui uso un campo di supporto con proprietà in questi giorni è quando la mia classe implementa INotifyPropertyChanged e devo attivare l'evento OnPropertyChanged quando viene modificata una proprietà.

Anche in queste situazioni ho impostato direttamente i campi di supporto quando i valori sono passati da un costruttore (non c'è bisogno di provare a lanciare OnPropertyChangedEvent (che sarebbe comunque NULL in questo momento), ovunque uso la proprietà stessa.

Non sai mai se potresti non aver bisogno di una traduzione dei dati in un secondo momento. Sei preparato a questo se nascondi i tuoi membri. Gli utenti della tua classe non noteranno se aggiungi la traduzione poiché l'interfaccia rimane la stessa.

La più grande differenza è che, se mai cambiate la vostra struttura interna, potete ancora mantenere i getter e i setter così come sono, cambiando la loro logica interna senza danneggiare gli utenti della vostra API.

Se in questo caso devi cambiare il modo in cui ottieni xey, puoi aggiungere le proprietà in un secondo momento. Questo è ciò che trovo più confuso. Se si utilizzano variabili membro pubbliche, è possibile modificarle facilmente in una proprietà in un secondo momento e utilizzare variabili private denominate _xe _y se è necessario memorizzare il valore internamente.

I setter e i getter sono cattivi in ??linea di principio (sono un cattivo odore di OO - smetterò di dire che sono un anti-pattern perché a volte sono davvero necessari).

No, tecnicamente non c'è alcuna differenza e quando voglio davvero condividere l'accesso a un oggetto in questi giorni, lo rendo occasionalmente pubblico invece di aggiungere un getter.

Il modo in cui setter e getter erano " Venduto " è che potresti aver bisogno di sapere che qualcuno sta ottenendo un valore o ne sta cambiando uno, il che ha senso solo con i primitivi.

Gli oggetti bag di proprietà come DAO, DTO e oggetti di visualizzazione sono esclusi da questa regola poiché non si tratta di oggetti in un vero "OO Design". significato della parola oggetto. (Non pensi a " Passing Messages " a un DAO, è semplicemente un mucchio di coppie attributo / valore).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top