Scelta tra classi e struct
Nota
Questo contenuto viene ristampato con l'autorizzazione di Pearson Education, Inc. da Framework Design Guidelines: Conventions, Idiomsn and Patterns for Reusable .NET Libraries, 2nd Edition. Tale edizione è stata pubblicata nel 2008 e il libro è stato completamente rivisto nella terza edizione. Alcune informazioni in questa pagina potrebbero non essere aggiornate.
Una delle decisioni di progettazione di base di ogni finestra di progettazione del framework è se progettare un tipo come classe (un tipo riferimento) o come struct (un tipo valore). Una buona comprensione delle differenze nel comportamento dei tipi di riferimento e dei tipi valore è fondamentale per effettuare questa scelta.
La prima differenza da considerare tra i tipi riferimento e i tipi valore è che i tipi riferimento vengono allocati nell'heap e sono sottoposti a Garbage Collection, mentre i tipi valore vengono allocati nello stack o inline in tipi contenenti e vengono deallocati quando lo stack si rimuove o quando il tipo contenitore viene deallocato. Di conseguenza, le allocazioni e le deallocazioni dei tipi valore sono in generale più economiche rispetto alle allocazioni e deallocazioni dei tipi di riferimento.
Successivamente, le matrici di tipi riferimento vengono allocate all'esterno della riga, il che significa che gli elementi della matrice sono solo riferimenti alle istanze del tipo di riferimento che si trovano nell'heap. Le matrici di tipi valore vengono allocate inline, ovvero gli elementi della matrice sono le istanze effettive del tipo valore. Di conseguenza, le allocazioni e le deallocazioni delle matrici di tipi di valore sono molto più economiche rispetto alle allocazioni e deallocazioni delle matrici di tipi di riferimento. Inoltre, nella maggior parte dei casi le matrici di tipi valore presentano una località di riferimento molto migliore.
La differenza successiva è correlata all'utilizzo della memoria. I tipi valore vengono racchiusi in boxing quando ne viene eseguito il cast in un tipo riferimento o in una delle interfacce implementate. Vengono rimossi dal boxing quando ne viene nuovamente eseguito il cast nel tipo valore. Poiché le caselle sono oggetti allocati nell'heap e vengono sottoposte a Garbage Collection, un'eccessiva conversione boxing e unboxing potrebbe avere un impatto negativo sull'heap, sul Garbage Collector e infine sulle prestazioni dell'applicazione. Al contrario, tale boxing non si verifica quando vengono eseguiti i cast dei tipi di riferimento. Per altre informazioni, vedere Boxing e unboxing.
Successivamente, le assegnazioni dei tipi di riferimento copiano il riferimento, mentre le assegnazioni di tipo valore copiano l'intero valore. Di conseguenza, le assegnazioni di tipi riferimento di grandi dimensioni sono più economiche rispetto alle assegnazioni di tipi valore di grandi dimensioni.
Infine, i tipi riferimento vengono passati per riferimento, mentre i tipi valore vengono passati per valore. Le modifiche apportate a un'istanza di un tipo riferimento influiscono su tutti i riferimenti che puntano all'istanza. Le istanze del tipo di valore vengono copiate quando vengono passate per valore. Quando viene modificata un'istanza di un tipo valore, naturalmente non influisce sulle copie. Poiché le copie non vengono create in modo esplicito dall'utente, ma vengono create in modo implicito quando vengono restituiti argomenti o valori restituiti, i tipi valore che possono essere modificati possono generare confusione in molti utenti. Pertanto, i tipi di valori devono essere non modificabili.
Come regola generale, la maggior parte dei tipi in un framework deve essere una classe. Esistono tuttavia alcune situazioni in cui le caratteristiche di un tipo valore rendono più appropriato usare gli struct.
✔️ PRENDERE IN CONSIDERAZIONE la definizione di uno struct invece di una classe se le istanze del tipo sono di piccole dimensioni e comunemente di breve durata o incorporate in altri oggetti.
❌ EVITARE di definire uno struct a meno che il tipo non abbia tutte le caratteristiche seguenti:
Rappresenta logicamente un singolo valore, simile ai tipi primitivi (
int
,double
e così via).Ha una dimensione dell'istanza inferiore a 16 byte.
Non è modificabile.
Non dovrà essere sottoposto a boxing frequentemente.
In tutti gli altri casi, è necessario definire i tipi come classi.
Parti protette da copyright © 2005, 2009 Microsoft Corporation. Tutti i diritti sono riservati.
Ristampato con l'autorizzazione di Pearson Education, Inc. da Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2a edizione di Krzysztof Cwalina and Brad Abrams, pubblicato il 22 ottobre 2008 da Addison-Wesley Professional nella collana Microsoft Windows Development Series.