Garantire l'immutabilità è una giustificazione per esporre un campo invece di una proprietà?

7

La guida generale per C # è di utilizzare sempre una proprietà su un campo pubblico. Questo ha senso: esponendo un campo, stai esponendo molti dettagli di implementazione. Con una proprietà, incapsula i dettagli in modo che siano nascosti dal consumo del codice e le modifiche di implementazione vengono disaccoppiate dalle modifiche dell'interfaccia.

Tuttavia, mi chiedo se a volte ci sia un'eccezione valida a questa regola quando si ha a che fare con la parola chiave readonly . Applicando questa parola chiave a un campo pubblico, si ottiene una garanzia extra: immutabilità. Questo non è solo un dettaglio di implementazione, l'immutabilità è qualcosa a cui un consumatore potrebbe essere interessato. L'utilizzo di un campo readonly lo rende parte del contratto pubblico e qualcosa che non può essere interrotto da modifiche o eredità future senza dover modificare anche il interfaccia pubblica. Questo è qualcosa che una proprietà non può offrire.

Quindi garantire l'immutabilità è un motivo legittimo per scegliere un campo readonly su una proprietà in alcuni casi?

(Per chiarimenti, non sto certo dicendo che dovresti sempre fare questa scelta solo perché il campo sembra essere immutabile al momento, solo quando ha senso come parte del design della classe e È inteso che l'utilizzo include l'immutabilità nel suo contratto. Sono principalmente interessato a risposte che si concentrino sul fatto che questo possa essere giustificato, piuttosto che su casi specifici in cui non lo è, come quando è necessario che il membro sia su interface o desideri per caricare pigro.)

    
posta Ben Aaronson 06.07.2015 - 01:10
fonte

4 risposte

4

I campi pubblici statici in lettura sono certamente a posto. Sono consigliati per determinate situazioni, ad esempio quando si desidera un oggetto costante con nome ma non è possibile utilizzare la parola chiave const .

I campi membri di Readonly sono un po 'più complicati. Non c'è molto vantaggio su una proprietà senza un setter pubblico, e c'è un grosso svantaggio: i campi non possono essere membri di interfacce. Quindi se decidi di rifattorizzare il tuo codice per operare su un'interfaccia invece che su un tipo concreto, dovrai modificare i tuoi campi di sola lettura in proprietà con getter pubblici.

Una proprietà pubblica non virtuale senza un setter protetto fornisce protezione contro l'ereditarietà, a meno che le classi ereditate abbiano accesso al campo di supporto. Puoi applicare completamente quel contratto nella classe base.

Non essere in grado di cambiare la "immutabilità" del membro senza modificare l'interfaccia pubblica della classe non è in questo caso una barriera. Di solito se vuoi cambiare un campo pubblico in una proprietà, va liscio, tranne che ci sono due casi che devi affrontare:

  1. Tutto ciò che scrive su un membro di quell'oggetto, ad esempio: object.Location.X = 4 è possibile solo se Location è un campo. Tuttavia, ciò non è rilevante per un campo readonly, poiché non è possibile modificare una struct readonly. (Questo presuppone che Location sia un tipo di valore - in caso contrario, questo problema non si applicherebbe comunque perché readonly non protegge da quel genere di cose.)
  2. Qualsiasi chiamata a un metodo che trasmette il valore come out o ref . Di nuovo, questo non è veramente rilevante per un campo readonly, perché i parametri out e ref tendono a essere modificati, ed è comunque un errore del compilatore passare un valore readonly come out o ref.

In altre parole, sebbene la conversione di un campo di sola lettura in una proprietà readonly interrompa la compatibilità binaria, l'altro codice sorgente dovrebbe essere ricompilato solo senza modifiche per gestire questa modifica. Ciò rende la garanzia davvero facile da rompere.

Non vedo alcun vantaggio per il campo membro readonly , e l'impossibilità di avere quel genere di cose su un'interfaccia è uno svantaggio sufficiente per me che non lo userei.

    
risposta data 06.07.2015 - 07:12
fonte
2

Dalla mia esperienza, la parola chiave readonly non è la magia che promette.

Ad esempio, hai una classe in cui il costruttore era semplice. Dato l'utilizzo (e il fatto che alcune proprietà / campi della classe sono immutabili dopo la costruzione) si potrebbe pensare che non ha importanza, quindi hai utilizzato la parola chiave readonly .

Più tardi, la classe diventa più complessa, così come il suo costruttore. (Diciamo che questo accade in un progetto che è sperimentale o ha una velocità abbastanza elevata che zuma fuori dall'ambito / controllo, ma è necessario farlo funzionare in qualche modo.) Troverete che i campi che sono readonly possono essere modificati solo all'interno del costruttore - non puoi modificarlo nei metodi anche se quel metodo è chiamato solo da un costruttore.

Questa limitazione tecnica è stata riconosciuta dai progettisti di C # e potrebbe essere risolta in una versione futura. Ma fino a quando non viene corretto, l'uso di readonly è più restrittivo e potrebbe incoraggiare alcuni stili di codifica sbagliati (mettendo tutto nel metodo del costruttore).

Come promemoria, né readonly né proprietà non di pubblico dominio forniscono alcuna garanzia di un "oggetto completamente inizializzato". In altre parole, è il progettista di una classe che decide cosa significa "completamente inizializzato" e come proteggerlo dall'uso involontario, e tale protezione generalmente non è infallibile, il che significa che qualcuno potrebbe trovare un modo per aggirarlo. p>     

risposta data 06.07.2015 - 08:36
fonte
1

I campi sono SEMPRE dettagli di implementazione. Non vuoi esporre i tuoi dettagli di implementazione.

Un principio fondamentale dell'ingegneria del software è che non sappiamo quali saranno i requisiti in futuro. Mentre il tuo campo readonly può essere buono oggi, non c'è nulla che possa suggerire che farà parte delle esigenze di domani. Cosa succede se domani è necessario implementare un contatore di visite per determinare quante volte è possibile accedere a quel campo? Cosa succede se è necessario consentire alle sottoclassi di sovrascrivere il campo?

Le proprietà sono così facili da usare e sono molto più flessibili dei campi pubblici che non riesco a pensare a un caso a uso singolo in cui sceglierei c # come lingua e utilizzare i campi pubblici di sola lettura su una classe. Se le prestazioni fossero talmente limitate da non riuscire a rispondere alla chiamata del metodo in più, probabilmente utilizzerei una lingua diversa.

Solo perché possiamo fare qualcosa con la lingua non significa che dovrebbe fare qualcosa con la lingua.

In realtà mi chiedo se i designer di linguaggio si pentiranno di rendere pubblici i campi. Non riesco a ricordare l'ultima volta che ho preso in considerazione l'utilizzo di campi pubblici non const nel mio codice.

    
risposta data 06.07.2015 - 07:49
fonte
-3

No. Non è una giustificazione.

L'utilizzo di readonly come garanzia di inimmaginabilità in una giustificazione non è più come un trucco.

Readonly significa che il valore è assegnato da un costruttore o quando la variabile è definita.

Penso che sarà una cattiva pratica

Se vuoi veramente garantire l'immutabilità, usa un'interfaccia con più pro e contro.

Esempio di interfaccia semplice:

    
risposta data 06.07.2015 - 07:26
fonte

Leggi altre domande sui tag