2011-08-17 22 views
9

Ho una classe che ha iniziato a essere mutevole, ma da allora l'ho resa immutabile. Devo cambiare per essere un struct? Che tipo di considerazioni vanno nella scelta dell'uno sull'altro? Il mio caso particolare è una classe di tipo Point (rappresenta una coordinata in un sistema di coordinate personalizzato) composta da 4 campi int e alcune proprietà per accedere agli stessi dati in modi diversi. Ho notato che String è una classe ed è immutabile, quindi ci deve essere qualche caso d'uso per questo.Classe immutabile vs Struttura immutabile

risposta

5

Generalmente no, non è necessario cambiarlo in una struttura. Solo perché è immutabile non significa che sia automaticamente un buon candidato per essere una struttura.

Una struttura deve essere piccola. Con i tuoi quattro ints è solo al limite consigliato di 16 byte in cui le prestazioni per le strutture iniziano a peggiorare.

Una struttura deve rappresentare una singola entità di qualche tipo. Forse la tua classe lo fa, ma dalla tua descrizione non sembra probabile.

Una struttura è più difficile da implementare correttamente rispetto a una classe. Dovrebbe comportarsi bene per cose come i confronti, quindi ci sono più cose da implementare di quanto ci si aspetti da una classe.

A meno che non si abbia una buona ragione per implementarlo come una struttura, come i problemi di prestazioni, si dovrebbe mantenere la classe come classe.

+0

Accetterò questa risposta sulla base del fatto che è la più utile in senso generale. Comunque penso che farò dei test delle prestazioni prima di accettare la raccomandazione di non usare una struct. La classe rappresenta una singola entità: un punto nello spazio. L'uguaglianza di valore ha un senso. Inoltre, questo è per un gioco, e sarà usato ovunque (vedi: rappresentazione di un punto nello spazio), quindi le prestazioni sono un problema.Inoltre, qualcosa che non potevi sapere: posso _probably_ (ho bisogno di testare) solo usare 2 'int''s e 2' byte''s, che riduce parecchio la dimensione della struct. –

+0

Sembra come quello che si sta descrivendo è perfettamente adatto ad essere una struttura, mi sento di raccomandare attuazione IComparable , IEquatable se avete intenzione di usarlo di alcuna raccolta – BrandonAGr

0

Dipende davvero da ciò che si desidera/deve rappresentare i dati contenuti al suo interno. Le strutture sono solitamente per la semplice rappresentazione o l'utilizzo per contenere più valori che potrebbero essere necessari più e più volte e le classi dovrebbero essere utilizzate quando l'oggetto stesso ha un comportamento richiesto che deve essere realizzato. Nel tuo caso, per motivi di semplicità e per permetterti di mantenere le tue proprietà, potresti anche renderlo un corso.

L'immutabilità è utilizzata in alcuni scenari. Ad esempio, se vuoi che qualcosa diventi un oggetto completamente nuovo ogni volta che viene modificato, puoi prendere in considerazione l'immutabilità (limiti di dati e così via). Se vuoi essere in grado di passare una classe con informazioni molto specifiche che non vuoi siano cambiate (magari alcuni oggetti DTO da un database che vengono creati e poi passati senza modifiche) in modo da non ottenere comportamenti strani se qualcuno cambia un valore.

+0

Le strutture possono ancora utilizzare le proprietà, quindi non è un argomento per mantenerlo come classe. –

+0

Consiglierei comunque di tenerlo come classe perché diamine perché no? Se in un secondo momento dovessi aggiungere funzionalità, dovresti tornare indietro e cambiarla da una struct a una classe, quindi aggiungere funzionalità ed entrambi in C# si comportano quasi allo stesso modo. Come programmatore C adoro le strutture ma in C# tendo a non usarle anche per oggetti semplici che hanno dati perché è semplicemente più facile mantenerli almeno per me. –

4

Come ho capito, l'utilizzo di una struct anziché di una classe è una questione di ottimizzazione. Le strutture vengono archiviate nello stack anziché nell'heap, quindi sono adatte come pacchetti leggeri di campi multipli utilizzati in grandi quantità. Vengono copiati ogni volta che passano tra i metodi, il che li rende più costosi, tuttavia ciò può prestarsi al tuo desiderio di immutabilità. Gli svantaggi dell'utilizzo di strutture includono le restrizioni naturali imposte dalla lingua.

Non sono affatto un esperto in materia, ma volevo portare questo aspetto. Qualcuno con più esperienza dovrebbe certamente intervenire ed espanderlo. Inoltre, ecco una discussione utile su di esso: When to use struct?

In definitiva, direi che se l'immutabilità è la tua unica considerazione, mantienila una classe (specialmente ora che vedo gli altri esprimere questa opinione). L'immutabilità può essere raggiunta indipendentemente dall'essere una struttura, quindi la questione non sembra fortemente correlata.

+0

La relazione, almeno nella mia mente, è che quasi tutte le 'struct's sono immutabili. Capisco che l'inverso non è vero; non tutti gli oggetti immutabili sono 'struct's. Ma mi è sembrata una buona cosa meditare mentre ero lì. –

+0

È una buona domanda +1. Ho sicuramente imparato dalla lettura degli altri post. Come ho detto, non c'è bisogno di cambiare se l'immutabilità è l'unica considerazione. Ma dai tuoi commenti sopra sembra che valga la pena considerare dopo tutto. –

1

Mantenerlo come una classe, a meno che non sia abbastanza piccolo che la struttura abbia un senso. Questo sarà raro. Il mio pensiero è che in generale i casi di "struttura" stanno rapidamente diminuendo. Se la semantica più forte fosse cotta all'inizio della lingua (immutabilità e caratteristiche dell'oggetto del valore del dominio), cambierei idea. Come esempio abbastanza nuovo, considera System.Tuple <>. Detto questo, mi limiterò a chiederti, semplicemente quale è il tuo oggetto (retoricamente parlando).

+0

Quello che è è spiegato nella domanda: "Il mio caso particolare è una classe di tipo" Point "(rappresenta una coordinata in un sistema di coordinate personalizzate) che è composta da 4 campi' int', più alcune proprietà per accedere al stessi dati in modi diversi. " –

+0

Se non ho perso nulla dichiarando il punto come struct, lo farei semplicemente perché un punto non ha un'identità diversa da * all * delle sue coordinate e perché le persone (programmatori) tendono ad assumere l'immutabilità per le strutture. Altrimenti, lo starei tenendo un corso. – Kit

0

Non vorrei passare a una struttura per l'immutabilità. La più grande differenza tra una struct e una classe è che una struct è un tipo di valore e una classe è un tipo di riferimento. Le strutture vengono copiate quando passate a un metodo, ma le classi passate a un metodo verranno passate per riferimento. Le classi possono essere immutabili proprio come le stutture.

2

Se è piccolo e immutabile, è preferibile creare una struttura. Soprattutto se hai grandi collezioni di molti punti. Se hai una lista di 1 milione di punti, allora ci sarà un sacco di spese generali per tutti quegli oggetti, in termini sia di tempo di GC che di 16 byte di overhead aggiuntivo per istanza di oggetto.

La stringa deve essere un tipo di riferimento perché non è possibile e non si desidera memorizzare un numero variabile di caratteri in uno stack, per non parlare della possibilità di stringhe interne e di condividere istanze. Questo msdn article contiene informazioni sul motivo per cui Tuple è stato creato come un tipo di riferimento.

+0

+1 e interessante articolo –

0

La semantica di strutture immutabili e oggetti di tipo classe immutabili sigillati sono quasi identici. Le prestazioni delle strutture 16 byte e quelle più piccole generalmente saranno migliori delle prestazioni di oggetti di tipo classe altrimenti identici, eccetto quando tali strutture sono typecast in Object o un tipo di interfaccia; tali tipi di esecuzione rallentano notevolmente le prestazioni delle strutture, ma non influiscono in modo particolare sulle prestazioni dei tipi di classe. Notare che v'è una grande differenza tra:

 
    void doSomethingWithIFoo(IFoo whatever); 

e

 
    void doSomethingWithIFoo<T>(T whatever) where T:IFoo; 

Passando una struttura alla prima sarà necessario che lo struct essere typecast a un tipo di interfaccia, mentre la seconda forma consentirà struct essere gestito come un suo tipo

+0

Credo che si intende: 'vuoto doSomethingWithIFoo (T qualunque cosa) dove T: IFoo; '? –

+0

@Matthew Scharley: corretto. Non solo la funzione generica non eviterebbe il pugilato come l'avevo scritta, ma non funzionerebbe molto bene con l'inferenza di tipo. – supercat