2009-03-20 8 views
7

MSDN dice che una classe che sarebbe 16 byte o meno sarebbe meglio gestita come una struttura [citation].
Perché è quello?
Significa che se una struttura è superiore a 16 byte è meno efficiente di una classe o è la stessa?
Come si determina se la propria classe ha meno di 16 byte?
Cosa limita una struttura ad agire come una classe? (oltre a disabilitare i costruttori senza parametri)Domande sulle strutture

+0

Puoi trovare molte informazioni sulle strutture C# qui: http://stackoverflow.com/questions/85553/when-should-i-use-a-struct-instead-of-a-class –

+0

Hai probabilmente lo avete già trovato, ma ce n'è ancora una tantum nel MSDN, qui: http://msdn.microsoft.com/en-us/library/ms229017.aspx –

+0

Ho appena scoperto che _right_ prima di postarlo. Grazie! – Malfist

risposta

6

Ci sono un paio diverse risposte a questa domanda, ed è un po 'soggettivo, ma alcune ragioni mi vengono in mente sono:

  • Structs sono value-type, le classi sono tipo di riferimento. Se stai utilizzando 16 byte per la memorizzazione totale, probabilmente non vale la pena di creare riferimenti di memoria (da 4 a 8 byte) per ognuno.
  • Quando si dispone di oggetti molto piccoli, possono essere spesso inseriti nello stack IL, anziché i riferimenti agli oggetti. Questo può davvero accelerare un po 'di codice, poiché stai eliminando una dereferenziazione della memoria dal lato del telefono.
  • C'è un po 'di "fluff" extra associato alle classi in IL, e se la tua struttura dati è molto piccola, nessuna di queste fluff sarà comunque usata, quindi è solo una junk extra che non ti serve.

La differenza più importante tra una struttura e una classe, tuttavia, è che le strutture sono di tipo valore e le classi sono di tipo di riferimento.

+0

Oh! sorry - dovrebbe aver scritto "Intermediate Language", che è una specie di abbreviazione per l'intero "CLR", Common Language Runtime - è la macchina virtuale che esegue il codice .NET. – Mike

+0

Ok, come la JVM? – Malfist

+0

Penso che IL ~ java bytecode e CLR ~ JVM – eglasius

0

In memoria, la struttura manterrà i dati direttamente, mentre una classe si comporterà più come un puntatore. Questo da solo fa una differenza importante, dal momento che passare la struct come parametro a un metodo passerà i suoi valori (copiandoli sullo stack), mentre la classe passerà il riferimento ai valori. Se la struttura è grande, copi molti valori per ogni chiamata di metodo. Quando è veramente piccolo copiare i valori e usarli direttamente sarà probabilmente più veloce di copiare il puntatore e doverli afferrare da un altro posto.

Informazioni sulle restrizioni: non è possibile assegnarlo a null (sebbene sia possibile utilizzare Nullable <>) e si deve inizializzarlo immediatamente.

+0

MSDN dice che una Struct viene archiviata nello stack, mentre una classe è archiviata nell'heap. – Malfist

+1

Sì, è vero. Le variabili di stack possono essere attraversate più velocemente delle variabili heap.Ma quando si passa una struct come parametro a un metodo, questo verrà copiato nello stack completamente prima che venga chiamato il metodo, mentre per una classe verrà copiato solo un puntatore. – Groo

2

Controllare questo collegamento, l'ho trovato su una delle risposte in SO oggi: .NET Type Internals. Puoi anche provare a cercare SO e googling per "tipi di riferimento e tipi di valore" per le differenze tra le strutture e le classi.

Cosa impedisce ad una struttura di comportarsi come una classe?

Ci sono molte differenze. Ad esempio, non puoi ereditare da una struttura.

Non è possibile avere metodi virtuali, quindi non è possibile utilizzare una struttura per implementare un'interfaccia. I metodi di istanza nelle strutture possono accedere ai campi privati ​​della struct, ma a parte il fatto che si comportano molto come le funzioni ausiliarie di "helper" (per le strutture immutabili, a volte non hanno nemmeno bisogno di accedere ai dati privati). Quindi li trovo non tanto "preziosi" quanto i metodi di classe.

+0

"non molto utile nell'aggiunta di metodi di istanza a una struttura" - Puoi approfondire ulteriormente? L'ho trovato leggermente utile, ad esempio aggiungendo un ToString() –

+0

La maggior parte delle classi dovrebbe essere sigillata, ma vedo il tuo punto. – Malfist

+0

@Neil: l'ho riformulato un po ', mi dispiace per la scarsa scelta di parole. – Groo

0

Ciò è dovuto al diverso modo in cui il CLR gestisce le strutture e le classi. Le strutture sono tipi di valore che significa che vivono nello stack anziché nell'heap gestito.È una buona regola per mantenere le strutture piccole perché una volta che si iniziano a passarle come argomenti del metodo, si incorre in un sovraccarico quando le strutture vengono copiate interamente quando passate a un metodo.

Poiché le classi passano una copia del loro riferimento ai metodi, esse comportano un sovraccarico molto minore quando vengono utilizzate come argomenti del metodo.

Il modo migliore per determinare la dimensione della classe è il numero totale di byte richiesti da tutti i membri della classe più 8 byte aggiuntivi per roba generale CLR (l'indice del blocco di sincronizzazione e il riferimento al tipo di l'oggetto).

0

Le strutture sono diverse dalle classi perché sono memorizzate nello stack e non nell'heap. Ciò significa che ogni volta che chiami un metodo con struct come parametro, una copia viene creata e passata al metodo. Ecco perché le grandi strutture sono estremamente inefficienti.

Scorrii attivamente l'utilizzo delle strutture, tuttavia, poiché potrebbe causare alcuni bug sottili: ad es. quando cambi un campo di una struttura, non verrà riflesso per il chiamante (perché hai solo cambiato la copia) - che è un comportamento completamente diverso rispetto alle classi.

Quindi i 16 byte penso sia una dimensione massima ragionevole di una struttura, ma nella maggior parte dei casi è preferibile avere una classe. Se vuoi ancora creare una struttura, cerca di renderla almeno immutabile.

3

Per "efficiente", probabilmente stanno parlando della quantità di memoria necessaria per rappresentare la classe o la struttura.

Sulla piattaforma a 32 bit, l'assegnazione di un oggetto richiede un minimo di 16 byte. Su una piattaforma a 64 bit, la dimensione minima dell'oggetto è 24 byte. Quindi, se la si guarda esclusivamente dalla quantità di memoria utilizzata, una struttura che contiene meno di 16 byte di dati sarà "migliore" della classe corrispondente.

Ma la quantità di memoria utilizzata non è l'intera storia. I tipi di valore (structs) sono fondamentalmente diversi dai tipi di riferimento (classi). Le strutture possono essere scomode da utilizzare e possono effettivamente causare problemi di prestazioni se non si presta attenzione.

La vera risposta, ovviamente, è quella di utilizzare qualsiasi cosa funzioni meglio nella vostra situazione. Nella maggior parte dei casi, starai molto meglio usando le lezioni.

0

La copia di un'istanza di una struttura richiede meno tempo rispetto alla creazione di una nuova istanza di una classe e alla copia di dati da una vecchia, ma le istanze di classe possono essere condivise e le istanze di struct non possono. Pertanto, "structvar1 = structvar2" richiede la copia di una nuova istanza di struct, mentre "classvar1 = classvar2" consente a classvar1 e classvar2 di fare riferimento alla stessa istanza di struct (senza doverne creare una nuova).

Il codice per gestire la creazione di nuove istanze di struct è ottimizzato per dimensioni fino a 16 byte. Le strutture più grandi vengono gestite in modo meno efficiente. Le strutture sono una vittoria nei casi in cui ogni variabile che contiene una struct manterrà un'istanza indipendente (cioè non c'è motivo di aspettarsi che qualsiasi particolare due variabili abbia istanze identiche); non sono molto vincenti (se sono una vittoria) nei casi in cui molte variabili potrebbero contenere la stessa istanza.