2011-01-22 21 views
6

Sono stato codificato .net da anni a questa parte mi sento come un n00b. Perché il seguente codice non funziona?Potrebbe essere così ovvio, ma perché fallisce?

byte[] a = Guid.NewGuid().ToByteArray(); // 16 bytes in array 
string b = new UTF8Encoding().GetString(a); 
byte[] c = new UTF8Encoding().GetBytes(b); 
Guid d = new Guid(c); // Throws exception (32 bytes recived from c) 

Aggiornamento

Approvata la risposta da CodeInChaos. La ragione per i 16 byte che diventano 32 byte può essere letta nella sua risposta. Anche indicato nella risposta:

il costruttore di default di UTF8Encoding ha il controllo degli errori disabilitato

IMHO l'encoder UTF8 dovrebbe lanciare un'eccezione quando si cerca di codificare un array di byte a stringa che contiene i byte non validi. Per rendere il framework .NET si comportano correttamente il codice dovrebbe essere scritto come segue

byte[] a = Guid.NewGuid().ToByteArray(); 
string b = new UTF8Encoding(false, true).GetString(a); // Throws exception as expected 
byte[] c = new UTF8Encoding(false, true).GetBytes(b); 
Guid d = new Guid(c); 
+1

Grazie per esserti liberato di 'var'. È come se l'intero punto di 'var' nascondesse gli errori. :) – MusiGenesis

risposta

6

Non ogni sequenza di byte è un UTF-8 stringa codificata valida.

Il GUID può contenere quasi tutte le sequenze di byte. Ma UTF-8 come regole specifiche per le quali sono consentite sequenze di byte se il valore è> 127. E un Guid spesso non seguirà queste regole.

Quindi quando si codifica la stringa danneggiata in un array di byte si ottiene un array di byte più lungo di 16 byte, che il costruttore di Guid non accetta.


La documentazione relativa UTF8Encoding.GetString afferma:

Con il rilevamento degli errori, una sequenza non valida provoca questo metodo per lanciare un ArgumentException. Senza il rilevamento degli errori, le sequenze non valide vengono ignorate e non viene generata alcuna eccezione.

e il costruttore predefinito di UTF8Encoding ha il controllo degli errori disabilitato (non chiedermi il motivo).

Questo costruttore crea un'istanza che non fornisce un segno di ordine byte Unicode e non genera un'eccezione quando viene rilevata una codifica non valida.
Nota
Per motivi di sicurezza, si consiglia alle applicazioni di abilitare il rilevamento degli errori utilizzando il costruttore che accetta un parametro throwOnInvalidBytes e impostando tale parametro su true.


Si potrebbe desiderare di utilizzare la codifica Base64 anziché UTF-8. In questo modo è possibile mappare qualsiasi sequenza di byte valida in una stringa e viceversa.

+0

Quindi perché il framework non genera un'eccezione quando riceve una stringa che non può codificare UTF8? –

+1

Non ho idea del motivo per cui hanno progettato le loro API in questo modo. IMO ignorando silenziosamente gli errori di codifica di default è stupido. – CodesInChaos

0

Perché var b è il tipo string, che significa che è una stringa unicode (2 byte per carattere). Nella seconda riga, stai creando una stringa di 16 caratteri da un array di 16 byte, ma quella stringa di 16 caratteri è archiviata in 32 byte.

Perché non solo fare questo:

var d = Guid.NewGuid(); 
+0

Ovviamente la stringa 'b' sarà trasmessa o memorizzata e quindi decodificata altrove. Che la decodifica avvenga direttamente dopo è solo perché questo è un semplice codice di esempio che dimostra il problema. – CodesInChaos

Problemi correlati