2010-05-02 5 views
5

Come sappiamo, in C# le strutture vengono passate per valore, non per riferimento. Quindi, se ho una struct con i seguenti membri di dati:C# struct con oggetto come membro dati

private struct MessageBox 
{ 
    // data members 
    private DateTime dm_DateTimeStamp; // a struct type 
    private TimeSpan dm_TimeSpanInterval; // also a struct 
    private ulong dm_MessageID; // System.Int64 type, struct 
    private String dm_strMessage; // an object (hence a reference is stored here) 
    // more methods, properties, etc ... 
} 

Così, quando un MessageBox viene passata come parametro, viene fatta una copia in pila, giusto? Che cosa significa in termini di come vengono copiati i membri dei dati? I primi due sono tipi di struct, quindi le copie dovrebbero essere fatte di DateTime e TimeSpan. Il terzo tipo è un primitivo, quindi è anche copiato. Ma per quanto riguarda dm_strMessage, che è un riferimento a un oggetto? Quando viene copiato, viene creato un altro riferimento alla stessa stringa, giusto? L'oggetto stesso risiede nell'heap e NON è copiato (ne esiste solo una nell'archivio.) Quindi ora dobbiamo fare riferimento allo stesso oggetto di tipo String. Se si accede ai due riferimenti da thread diversi, è concepibile che l'oggetto String possa essere corrotto modificando contemporaneamente da due direzioni diverse. La documentazione MSDN dice che System.String è thread-safe. Significa che la classe String ha un meccanismo integrato per impedire che un oggetto venga corrotto esattamente nel tipo di situazione qui descritta? Sto cercando di capire se la mia struttura MessageBox ha potenziali difetti/insidie ​​essere una struttura rispetto a una classe. Grazie per qualsiasi input.

Source.Energy.

+0

Ecco una domanda simile con la risposta di Jon Skeet alla fine http://bytes.com/topic/c-sharp/answers/553351-what-happens-reference-type-valuetype-struct –

risposta

4

Le stringhe non possono essere "danneggiate" dall'accesso multithread perché sono immutabili.

Tuttavia, dovresti evitare di rendere le tue strutture mutabili. Leggi this question e le risposte per ulteriori informazioni.

Sto cercando di capire se la mia struttura MessageBox ha potenziali difetti/insidie ​​essere una struttura rispetto a una classe.

Probabilmente non dovrebbe essere una struttura. Vedere le linee guida su MSDN per choosing between a class and a struct.

non definiscono una struttura meno che il tipo ha tutte le caratteristiche seguenti:

  • Esso rappresenta logicamente un singolo valore, simili ai tipi primitivi (integer, doppia, e così via).
  • Ha una dimensione dell'istanza inferiore a 16 byte.
  • È immutabile.
  • Non dovrà essere inserito frequentemente in una scatola.

Credo che la vostra MessageBox rompe definitivamente il primo e secondo le linee guida, e forse anche la terza a seconda di quali metodi sono disponibili.

+0

Grazie per le risposte ragazzi. Le tue risposte mi hanno indirizzato nella giusta direzione, e ho trovato * diversi * post relativi a strutture e immutabilità, quindi ora penso di capire molto meglio i concetti. C'è un'altra domanda di follow-up che vale la pena affrontare: Se le strutture sono create nello stack (è corretto, non è vero?), E gestisco una coda (cioè System.Collection.Queue) di Structures, vuol dire che TUTTE le strutture in coda sono memorizzate nello stack? Probabilmente non è quello che voglio, eh? Soprattutto perché uno dei membri dei dati è una stringa, che potrebbe crescere a lungo. –

+1

Non è corretto che le strutture vengano sempre create nello stack. E dovresti cercare di non basare la tua comprensione delle classi e delle strutture sul fatto che siano memorizzate nello stack o nell'heap. Questo è un dettaglio di implementazione e potrebbe cambiare in futuro (ma probabilmente non lo farà). Ma per rispondere alla tua domanda, il * riferimento * a una stringa può essere memorizzato nello stack o nell'heap, ma i * dati di carattere * in una stringa si troveranno nell'heap anche per le stringhe nelle strutture. –

0

Da una prospettiva di GC, passare una singola struttura non è molto diverso dal passare i campi come parametri individuali. Non c'è certamente nulla di cui preoccuparsi quando si passa una stringa in una struttura, passando una stringa come parametro semplice.

Le stringhe sono immutabili, quindi sono impossibili da corrompere, indipendentemente da quanti thread le condividano.

2

In primo luogo, la prima frase implica che si pensi che le classi vengano passate per riferimento. Questo non è il caso - il riferimento è passato per valore (di default).Vedi my article on parameter passing per maggiori dettagli. Quando lo capisci, può rendere più chiari altri aspetti.

La tua domanda è davvero di due cose diverse:

  • Come valori struct sono copiati
  • quanto sia sicuro per condividere le stringhe tra le discussioni

penso che vi aiuterà se si separare i due.

Quando si copia il valore di una struttura, i membri vengono trattati allo stesso modo indipendentemente dal fatto che siano tipi di valori o tipi di riferimento. Il valore viene semplicemente copiato, bit per bit. La cosa importante da capire è che il valore di dm_strMessage è un riferimento, non un oggetto stringa. Quel riferimento è copiato.

Questo non è più dannoso di questo codice:

string message = GetMessageFromSomewhere(); 
string otherMessage = message; 

Esattamente la stessa cosa accade: il valore di message viene copiato nella otherMessage: le due variabili hanno lo stesso valore, che è un riferimento ad una singola oggetto stringa.

Finora, questo non ha nulla a che fare con la filettatura. Ora se condividi una stringa di riferimento tra più thread, è sicuro - perché le stringhe sono immutable. Non è possibile modificare il contenuto di un oggetto stringa, quindi due stringhe possono perfettamente leggere i dati dallo stesso oggetto senza rischi di corruzione. Lo stesso è non vero di molti altri tipi in .NET. Ad esempio, non è sicuro condividere uno List<T> tra più thread che potrebbero modificare l'elenco.

+0

Giusto, Jon, grazie. Per chiarire: nel tuo esempio, il messaggio variabile (di tipo String) è un riferimento a un oggetto String, quindi quando il messaggio viene passato come parametro viene copiato il riferimento stesso, il che significa che è passato per valore, come hai detto tu. I dati che rappresentano l'oggetto String risiedono nell'heap e NON sono assolutamente copiati. Quindi, dopo che il messaggio è passato e supponendo che non vada fuori ambito, finiamo con due riferimenti allo stesso oggetto String. Tutto sopra è preciso e corretto? E sì, ora vedo che la mia domanda originale non deve fare molto con la sicurezza di threading/thread. –

+0

Sì, è tutto corretto –