Utilizzo di un metodo SetProperty per impedire modifiche accidentali a una proprietà

6

È buona o cattiva pratica eseguire quanto segue:

public class MyClass {
  public MyType MyProperty { get; private set; }

  public void SetMyProperty(MyType myProperty) {
    MyProperty = myProperty;
  }
}

La mia intenzione è impedire che MyProperty venga modificato accidentalmente al di fuori della classe. Tuttavia, può essere modificato se necessario.

Inoltre, se MyType è un tipo di riferimento, il private set impedisce, ad esempio:

instanceOfMyClass.MyProperty.SomeField = 2;

In altre parole, renderà MyProperty e tutti i suoi membri in sola lettura, o solo il riferimento a MyProperty ?

Scusa se questa sembra una domanda non intelligente; Temo di essere un principiante.

    
posta James 31.10.2011 - 21:31
fonte

5 risposte

10

My intention is to prevent MyProperty from being accidentally changed outside the class. However, it can be changed if needed.

Non vedo il punto di farlo, per essere onesti. Chiamando

myClass.MyProperty = new MyType();

non è meno intenzionale che chiamare

myClass.SetMyProperty(new MyType());

In termini di leggibilità, penso che tu stia molto meglio con l'approccio setter più intuitivo invece che con un metodo separato. E se non vuoi consentire a nessuno di modificare il valore di MyProperty , non permetterlo neanche tramite un setter o un metodo.

In other words, will it make MyProperty and all its fields readonly, or just the reference to MyProperty?

Solo il riferimento a MyProperty . MyType deve essere un tipo immutable se vuoi impedire alle persone di cambiare il suo proprietà.

    
risposta data 31.10.2011 - 21:38
fonte
4

Avere un setter privato è una pratica perfettamente valida e lo faccio spesso io stesso. Questo fa parte dell'incapsulamento, che è uno dei fondamenti di OOP.

Tuttavia, fornire un metodo pubblico per l'impostazione è piuttosto inutile: se vuoi essere in grado di impostare il valore, usa un setter pubblico.

Come hai chiesto, avere un setter privato non permetterà che il valore del campo sottostante cambi al di fuori della classe (il compilatore ne genera uno per te - c'è ancora un campo sottostante). Questo a meno che tu non fornisca funzioni pubbliche che causeranno modifiche a questo valore.

    
risposta data 31.10.2011 - 21:38
fonte
2

Se avessi voluto utilizzare i metodi "SetProperty" tutto il giorno, avrei programmato in java.

Inoltre, se si dispone di una proprietà pubblica di acquisizione, anche se tale proprietà ha un set privato, i membri del valore della proprietà possono essere modificati. Alcune classi forniscono wrapper "di sola lettura" per risolvere questo problema, come i molti della classe dell'array: collegamento

    
risposta data 31.10.2011 - 21:51
fonte
1

Fornire un getter consente comunque di modificare le proprietà della classe. Vorrei clonare l'istanza se volessi evitarlo

private MyType _myProperty;
public MyType MyProperty { get { return new MyType(_myProperty); } set { _myProperty = value; } }
    
risposta data 19.07.2012 - 10:14
fonte
0

Se qualcosa si comporterebbe come una proprietà di lettura-scrittura, dovrebbe generalmente essere implementata usando una proprietà di lettura-scrittura. D'altra parte, il fatto che il valore di una proprietà possa essere cambiato non significa che si comporterà come una proprietà di lettura-scrittura. Suggerirei che, in generale, qualcosa dovrebbe essere implementato come proprietà di lettura-scrittura solo se agisce come una proprietà "pulita" (descritta di seguito), anche se noterei che molte classi in .net usano proprietà di lettura-scrittura in modi che non sono conforme a ciò che suggerisco. Direi che in molti casi ciò deriva dalla pressione del tempo per implementare il framework prima che il pieno background filosofico fosse completamente elaborato.

Considererei una proprietà read-write come pulita se:

  1. La lettura non avrà mai alcun effetto collaterale e produrrà sempre lo stesso valore in assenza di una chiamata di metodo o di scrivere su quella proprietà.
  2. Leggendolo e poi riscrivendo il valore letto non avrà alcun effetto.
  3. Una lettura che segue una scrittura senza una chiamata al metodo intermedio produrrà sempre il valore scritto.
  4. Scrivere la proprietà più di una volta senza chiamate di metodo intermedio avrà lo stesso effetto di eseguire solo l'ultima scrittura.
  5. In assenza di chiamate al metodo intermedio, l'effetto di impostare una proprietà pulita su X e quindi di impostare un'altra proprietà su Y sarà lo stesso di impostare l'altra proprietà su Y e quindi impostare quella pulita su X.

Si noti che è perfettamente ammissibile che una scrittura in una proprietà "pulita" influenzi lo stato di altre proprietà di sola lettura. L'effetto dell'impostazione di più proprietà dovrebbe dipendere dai valori scritti, ma non dalla sequenza in cui si verificano le scritture. Se myRect è inizializzato su (X = 1, Y = 2, Larghezza = 3, Altezza = 4), l'effetto di MyRect.X=2; MyRect.Top = MyRect.Right; dovrebbe essere uguale a MyRect.X = 2; MyRect.Top = 5; o MyRect.Top = 5; MyRect.X = 2; , anche se non sarebbe essere uguale a MyRect.Top = MyRect.Right; MyRect.X = 2; .

Molte classi .net usano le proprietà in modi che sono da queste definizioni "sporche". Utilizzando queste definizioni, ad esempio, StringBuilder. Length dovrebbe essere probabilmente una proprietà di sola lettura, ma Text potrebbe probabilmente essere una proprietà di lettura-scrittura (la lettura di Text sarebbe equivalente a ToString() , mentre la scrittura sarebbe equivale a eliminarlo e a fare Append ).

Ci sono varietà di situazioni in cui si può essere in grado di modificare le proprietà di un oggetto, ma non dovrebbero essere considerate "pulite proprietà di lettura-scrittura". Tra questi:

  1. Un rettangolo che memorizza (X, Y, Larghezza, Altezza) e li espone come proprietà di lettura-scrittura potrebbe avere una proprietà 'Giusta', ma il tentativo di impostarlo influenzerebbe uno degli altri.
  2. Un oggetto può contenere un riferimento a un oggetto "IDisposable" e ci si può aspettare che venga chiamato "Dispose" su di esso quando non è più necessario. Un metodo 'SetXXAndTakeOwnership ()' offrirebbe semantica più chiara (chiamata 'Dispose' il vecchio oggetto prima di impostare la proprietà) offrirebbe semantica molto più chiara di una proprietà di lettura-scrittura.
  3. Alcuni oggetti possono avere proprietà che possono essere impostate solo su determinate combinazioni di valori; avere un metodo per impostare tutte queste proprietà in una volta può essere molto più bello che dover impostare le proprietà singolarmente e preoccuparsi del sequenziamento. 'ProgressBar' è particolarmente icky in questo senso, dal momento che le sue proprietà devono essere scritte in un ordine che dipende da vecchi e nuovi valori; se un 'ProgressBar' sta attualmente indicando 7/9 fatto, cambiandolo a 3/5 è necessario scrivere 'Valore' prima di 'Massimo', ma impostandolo su 14/19 è necessario scrivere prima di aggiornare 'Massimo'. Un metodo 'SetFraction' che accettava i parametri sia per il valore sia per il massimo, e aggiornato contemporaneamente, sarebbe stato molto meglio.
  4. Alcune proprietà come il tempo rimanente su un timer possono cambiare tra il momento in cui sono scritte e il tempo di lettura. Tali cose possono essere perfettamente fini come proprietà di sola lettura (leggerle richiederebbe del tempo, e l'atto di prendere tempo potrebbe influenzare le letture future, ma tale effetto collaterale non sarebbe diverso da qualsiasi altro codice che il sistema potrebbe eseguire) ma violerebbe la regola che una proprietà pulita dovrebbe restituire l'ultimo valore letto.

Se una di queste condizioni (o una delle tante altre - l'elenco è difficilmente esauriente) si applica, usa un metodo SetXX piuttosto che una proprietà read-write.

    
risposta data 18.07.2012 - 18:49
fonte

Leggi altre domande sui tag