2016-06-16 21 views
10

Semplicemente curioso, sta cambiando la dimensione di un tipo di struttura/valore come una modifica in C#? Le strutture tendono ad essere più sensibili in termini di layout della memoria poiché la loro modifica influisce direttamente sulle dimensioni degli array/altre strutture. Ci sono esempi di codice che si rompono, sia in termini di binari che di origine, dopo che il layout di una struttura in una libreria che usa è cambiato?La dimensione di una struttura sta cambiando in C#?

NOTA: Per "interruzioni", intendo che non riesce a compilare affatto o che IL è invalidato. Così, per esempio non vorrei considerare questo un cambiamento di rottura:

// My.Library v1 
public struct MyStruct {} 

// My.Library v2 
public struct MyStruct { int _field; } 

// App code 
using My.Library; 
using System.Runtime.InteropServices; 

Console.WriteLine(Marshal.SizeOf<MyStruct>()); // before printed 1, now prints 4 

perché corre ancora.

+1

Si sta utilizzando InteropServices per interagire con codice non gestito? Se è così, la risposta è sì, è un cambio di rottura. Se no, la risposta è più sfumata. –

+0

Scusa, non capisco la tua domanda ... Hai ricompilato l'assemblea, quindi tutto dovrebbe andare bene? –

+0

Il jitter nasconde molti peccati. Le dimensioni della struttura non hanno alcun ruolo al momento della compilazione, solo in fase di esecuzione. Avere un campo non inizializzato potrebbe essere sorprendente. –

risposta

8

La modifica della dimensione aggiungendo i campi è ok per il codice strettamente gestito.

L'aggiunta di campi è una modifica senza interruzioni poiché il codice verrà reimpostato con il nuovo tipo e tutte le allocazioni utilizzeranno la dimensione corretta. Poiché è di tipo valore, i nuovi campi saranno comunque inizializzati correttamente con valori vuoti.

La rimozione/modifica dei tipi di campi o proprietà esistenti è decisamente un cambiamento.

I tipi di valore sono sigillati, quindi nessun'altra libreria può derivare da quel tipo, quindi a differenza delle classi non possono creare problemi con "questa classe derivata non ha implementato un nuovo metodo di proprietà/interfaccia virtuale".

Nota: se un tipo di valore viene utilizzato per l'interoperabilità o di qualsiasi altro tipo di serializzazione binaria al di fuori del vostro controllo di qualsiasi cambiamento sta rompendo.

I.e. qualcun altro ha utilizzato MyLib.Point {int x;int y;} per salvare un elenco di punti con serializzazione binaria in un file. Se ora "MyLib" aggiunge un nuovo campo a MyLib.Point, i dati serializzati non possono più essere letti con la serializzazione binaria. Problema simile con l'interoperabilità nativa.

3

Sì, le incompatibilità del codice sorgente sono sicuramente possibile, anche nel codice rigorosamente gestito, se si aggiunge un nuovo campo. Prendendo il vostro esempio, questo compila con la versione 1, ma non la versione 2:

MyStruct s; 
Console.WriteLine(s); 

La ragione è che C# consente a un locale struct da utilizzare se tutti i campi sono stati assegnati valori. Nella versione 1, non ci sono campi quindi s è "definitivamente assegnato". Tuttavia se un campo viene aggiunto nella versione 2, anche se è privato, questo non verrà più compilato perché s non è più assegnato definitivamente.

Questo caso deve essere compatibile binario poiché il CLR garantisce l'inizializzazione dei campi ai valori predefiniti.

Jared Parsons aveva uno good blog post sull'argomento dei campi privati ​​nelle strutture in cui descrive in dettaglio altri casi in cui modificare i dettagli di implementazione privata sarebbe pericoloso (per codice non sicuro) o rottura.

+0

Venerato. Grazie per il post del blog, a proposito, è stata una lettura interessante. –

Problemi correlati