Le raccomandazioni MSDN (elencati in un'altra risposta) offre qualche indicazione. Per le prestazioni dovresti considerare il loro utilizzo e dove conta la differenza tra le strutture e le classi. La cosa più importante è usare solo le strutture quando il tipo è un tipo di valore effettivo, cioè la semantica valore. L'utilizzo di una classe per un tipo di valore o una struttura per qualcosa che dovrebbe essere un tipo di riferimento genererà rapidamente risultati confusi con copie non intenzionali o riferimenti non voluti. Ricorda inoltre che le strutture dovrebbero essere sempre immutabili.
Solo in situazioni estremamente sensibili alle prestazioni si dovrebbe ignorare una qualsiasi di queste regole di base (Caso in questione: il framework infrange le regole per la struttura List.Enumerator!).
considerazioni Perf per le strutture vs classi:
Se si passa lo struct come argomento di un metodo, si creerà una copia della struct ogni volta. Questo è il motivo per cui i documenti raccomandano di non rendere le strutture più grandi di 16 byte.
double Distance(Vector3D a, Vector3D b) // Copies both 24-byte structs
{
return Math.Sqrt((a.X - b.X *....);
}
Nello scenario precedente, un 3D vettore di 3 doppie renderebbe 24 byte e sarebbe più grande della raccomandata 16, ma mi piacerebbe ancora sostengono che una struct ha senso dal momento che è chiaramente un tipo di valore, in particolare hai un Vector2D contenente due doppi (16 byte) che è una struttura!
La chiave per utilizzare le strutture in modo efficiente e dove le loro prestazioni brilla davvero è usarle per la località di cache ed evitare molte allocazioni. Per riutilizzare l'esempio Vettoriale sopra, se si dispone di questo metodo
double AverageDistanceFromOrigin(Vector3D[] points) // Single reference passed
{
double sum = 0.0;
for(...)
sum += Math.Sqrt(points[i].X... + ... + ...) // No copies
return sum/points.Length;
}
Si può notare una buona differenza di prestazioni a favore delle strutture. Il motivo è che ora si sta passando un singolo riferimento (l'array) al metodo, quindi non c'è nessun overhead aggiuntivo per copiare la struct per call (si noti che il metodo non chiama un metodo distance per ogni voce nell'array) .
La matrice di strutture viene inoltre impostata in modo consecutivo in memoria come [x1, y1, z1, x2, y2, ...] in modo che la CPU carichi, ad es. 16 coordinate alla volta nella cache, portando a pochi errori di cache. Confrontalo con un'implementazione class Vector3D
: ora verrà assegnata una matrice di vettori e ogni voce nell'array sarà anche essere un riferimento che deve essere assegnato all'heap e successivamente eliminato. L'array è ora una matrice di riferimenti [ref to v1, ref to v2, ref to v3] ognuno dei quali può avere qualsiasi indirizzo nell'heap e non può sedersi uno accanto all'altro a. Questo può portare a molti più errori di cache rispetto al caso struct. solo
- Usa struct se il tipo ha valore semantica (e viceversa).
- Non passare le grandi strutture singolarmente ai metodi; Operare su liste/matrici di strutture per evitare di copiare
- Non considerare il limite di 16 byte come un limite rigido: è possibile utilizzare strutture molto più grandi, ma ricordarsi di evitare di passarle singolarmente ai metodi.
L'utilizzo di una struttura eviterà un ulteriore dereferenziamento di un riferimento per accedere ai campi della struttura ma al costo aggiuntivo che ogni volta che è necessario passare la struttura attorno ad esso viene copiato a meno che non lo si passi esplicitamente per riferimento. Questo può essere utile, ma molto probabilmente l'utilizzo di strutture su classi sarà dannoso per il tuo codice. –
Ciò che può essere più significativo è evitare l'allocazione dinamica. le strutture, ad esempio i tipi di valore, si comportano in modo molto simile agli inte; quando li crei sono memoria locale o statica che è significativamente più economica dell'allocazione dinamica. Il rovescio della medaglia è, come dice Martin, che il valore viene copiato per assegnazione, reso, ecc. Questo è più costoso solo per gli oggetti di grandi dimensioni, piuttosto che restituire un riferimento. –