Le proprietà dovrebbero avere effetti collaterali

18

Le proprietà in C # dovrebbero avere effetti collaterali oltre alla notifica di un cambiamento nei suoi stati?

Ho visto le proprietà utilizzate in molti modi diversi. Da proprietà che caricheranno il valore la prima volta che si accede a proprietà che hanno enormi effetti collaterali come causare un reindirizzamento a una pagina diversa.

    
posta Erin 08.06.2011 - 04:34
fonte

6 risposte

39

Suppongo che tu stia parlando di proprietà di sola lettura , o almeno di proprietà getter , poiché una proprietà setter è, in quasi ogni istanza, avrà effetti collaterali. Altrimenti non è molto utile.

In generale, un buon design segue il principio di sorpresa minima . Non fare cose che i chiamanti non si aspettano che tu faccia, specialmente se queste cose potrebbero cambiare i futuri risultati.

In generale , ciò significa che i getter di proprietà non dovrebbero avere effetti collaterali.

Tuttavia , facciamo attenzione a ciò che intendi per "effetto collaterale".

Un effetto collaterale è, tecnicamente, qualsiasi modifica di stato. Potrebbe essere uno stato accessibile al pubblico o ... potrebbe essere uno stato totalmente privato.

I caricatori pigri / differiti sono un esempio di stato quasi esclusivamente privato. Finché non è responsabilità del chiamante liberare quella risorsa, in realtà si sta riducendo la sorpresa e la complessità in generale utilizzando l'inizializzazione posticipata. Un chiamante normalmente non si aspetta di dover esplicitamente segnalare l'inizializzazione di una struttura interna . Quindi, l'inizializzazione pigra non viola il principio di cui sopra.

Un altro esempio è una proprietà sincronizzata. Affinché un metodo sia sicuro per i thread, dovrà spesso essere protetto da una sezione critica o mutex. Entrare in una sezione critica o acquisire un mutex è un effetto collaterale; stai modificando lo stato, di solito lo stato globale . Tuttavia, questo effetto collaterale è necessario al fine di prevenire un tipo di sorpresa peggio - la sorpresa dei dati modificati (o peggio, parzialmente modificati) da un altro thread.

Quindi allenterei un po 'la restrizione a quanto segue: Le letture delle proprietà non dovrebbero avere effetti secondari visibili o effetti collaterali che cambiano la loro semantica .

Se non c'è modo per un chiamante di essere mai influenzato da, o anche consapevole di un effetto collaterale, allora quell'effetto collaterale non sta facendo alcun danno. Se fosse impossibile per te scrivere un test per verificare l'esistenza di un particolare effetto collaterale, allora è abbastanza localizzato da etichettarlo come un dettaglio di implementazione privato, e quindi privo di legittime preoccupazioni per il mondo esterno.

Ma fai attenzione; come regola generale, dovresti cercare di evitare effetti collaterali, perché spesso ciò che potresti pensare di essere un dettaglio di implementazione privato può inaspettatamente fuoriuscire e diventare pubblico.

    
risposta data 08.06.2011 - 04:57
fonte
5

Risponderò alla tua domanda con una domanda: cosa succede quando modifichi la proprietà Width di un modulo?

Appena fuori dalla mia testa, questo sarà:

  • Modifica il valore del campo di supporto.
  • attiva un evento.
  • Modifica le dimensioni del modulo, segnala la modifica al gestore di finestre e richiedi un aggiornamento.
  • Avvisa i controlli sul modulo della modifica in modo che tutti quelli che devono cambiare dimensione o posizione quando il modulo viene ridimensionato può farlo.
  • Causa tutti i controlli che hanno cambiato gli eventi di fuoco e comunica al gestore di finestre che è necessario ridisegnarli.
  • Probabilmente anche altre cose.

(Disclaimer: Sono uno sviluppatore Delphi, non uno sviluppatore .NET.Questo potrebbe non essere accurato al 100% per C #, ma scommetto che è piuttosto vicino, soprattutto considerando quanto del framework .NET originale fosse basato su Delphi .)

Tutti questi "effetti collaterali" si verificano quando si modifica la proprietà Width su un modulo. Qualcuno di loro sembra inappropriato o scorretto in qualche modo?

    
risposta data 08.06.2011 - 04:49
fonte
5

Dai un'occhiata a Microsoft Design Rules , in particolare uno di loro:

CA1024: usa le proprietà dove appropriato

...A method is a good candidate to become a property if one of these conditions is present:

  • Takes no arguments and returns the state information of an object.
  • Accepts a single argument to set some part of the state of an object.

Properties should behave as if they are fields; if the method cannot, it should not be changed to a property. Methods are better than properties in the following situations:

  • The method performs a time-consuming operation. The method is perceivably slower than the time that is required to set or get the value of a field.
  • The method performs a conversion. Accessing a field does not return a converted version of the data that it stores.
  • The Get method has an observable side effect. Retrieving the value of a field does not produce any side effects.
  • The order of execution is important. Setting the value of a field does not rely on the occurrence of other operations.
  • Calling the method two times in succession creates different results.
  • The method is static but returns an object that can be changed by the caller. Retrieving the value of a field does not allow the caller to change the data that is stored by the field.
  • The method returns an array...
    
risposta data 08.06.2011 - 12:53
fonte
1

Credo che le proprietà non dovrebbero avere effetti collaterali. Esiste tuttavia un'eccezione a questa regola: il caricamento lazy. Se vuoi caricare qualcosa in una proprietà pigro, va bene, perché il client non può dire che il caricamento lazy sta andando, e generalmente non gli interessa.

EDIT : Oh, un'altra cosa: lanciare un evento che dice "PropertyXYZ cambiato!" (ad esempio INotifyPropertyChanged ) - sta bene sui setter.

    
risposta data 08.06.2011 - 04:46
fonte
1

Oltre al caricamento lazy menzionato in precedenza, c'è anche il caso delle funzioni di logging. Questi sarebbero rari ma non esclusivi.

    
risposta data 08.06.2011 - 06:26
fonte
1

Non ci sono quasi assoluti nella programmazione, per rispondere alla tua domanda dobbiamo guardare alcune proprietà desiderabili degli oggetti e vedere se è qualcosa da applicare al nostro caso

  1. Vogliamo che le classi siano facilmente testabili.
  2. Vogliamo che le classi supportino la concorrenza
  3. Vogliamo che le classi siano facili da ragionare per terze parti

Se rispondiamo sì a alcune di queste domande, probabilmente è una buona idea pensare molto attentamente alle proprietà e ai loro effetti collaterali. Presumo che quando dici effetti collaterali intendi gli effetti secondari secondari poiché l'aggiornamento del valore è di per sé un effetto collaterale.

Più effetti collaterali in generale più difficile sarà una classe da testare. Gli effetti collaterali più secondari saranno la concorrenza più difficile da gestire, ma si tratta di un problema molto difficile che probabilmente richiede comunque alcuni importanti progetti.

Il grande trucchetto è probabilmente per le persone che considerano la tua classe come una "scatola nera", non sarebbe prontamente disponibile che alcuni stati sono cambiati solo perché hanno letto una proprietà o che alcune altre proprietà cambiano perché un altro cambia ( che potrebbe portare a aggiornamenti a cascata).

Quindi, in generale no, vogliamo che le proprietà siano più facili da ragionare e più semplici possibili, questo è un po 'implicito nella decisione di progettazione altrimenti sarebbe un metodo. Tuttavia, un buon programmatore può sempre violare le regole, ma assicurati di avere una buona ragione:)

    
risposta data 08.06.2011 - 08:59
fonte

Leggi altre domande sui tag