2011-10-19 3 views
9

C'è qualcuno in grado di spiegarmi questo strano comportamento?Perché dovrei circondare esplicitamente con "deselezionato"?

int i = 0x1234; 
    byte b1 = (byte)i; 
    byte b2 = (byte)0x1234;   //error: const value '4660' can't convert to byte (use unchecked) 
    byte b3 = unchecked((byte)0x1234); 
    byte b4 = checked((byte)i);  //throws 
    byte b5 = (byte)(int)0x1234; //error: same as above 

NOTA: È un'applicazione vuota Console, con NO aritmetica checking abilitata (come default è). Grazie a tutti in anticipo.

EDIT: Dovevo essere abbastanza chiaro, ma non per tutti.

So che una parola non può essere inserita in un byte. Ma, per impostazione predefinita, un programma C# consente determinate operazioni "pericolose", principalmente per motivi di prestazioni.

Analogamente, è possibile sommare due interi di grandi dimensioni insieme e senza alcun overflow.

La mia meraviglia riguardava l'errore di compilazione sopra riportato: il cast b1/assegnazione è compilato, il b2 non può essere compilato. Apparentemente non c'è differenza, perché entrambi hanno Int32 con lo stesso valore.

Spero sia chiaro ora.

+3

Non parlo C# e non so cosa significhi "checked" e "unchecked", ma so che non è possibile inserire un numero esadecimale di quattro cifre in un byte. –

+1

Quale comportamento è 'strano' per te? Ci hai fornito ** passaggi per riprodurre ** e ** risultati effettivi **, ma non ** risultati attesi **. – AakashM

risposta

11

Stai inciampare in una parte della sezione 7.19 del C# 4 spec:

A meno che un'espressione costante è esplicitamente collocato in una unchecked contesto, overflow che si verificano nelle operazioni e conversioni aritmetiche integrale di tipo durante la valutazione fase di compilazione dell'espressione causano sempre errori di compilazione.

In sostanza, il punto è che anche se sei felice per consentire le operazioni di overflow esecuzione tempo, se si sta cercando di utilizzare un'espressione costante che non può essere convertito nel tipo di destinazione al momento della compilazione, devi dire al compilatore che tu non sappia quello che stai facendo.

Ad esempio, in questo caso si sta perdendo informazioni - sarà equivalente a

byte b3 = 0x34; 

quindi faresti normalmente essere meglio solo che specifica che, per darvi il codice più chiaro che doesn ingannare il lettore. E 'relativamente raro che si desidera traboccare in un continuo - il più delle volte si deve solo specificare il valore valido, invece.

+3

Sembri un avvocato che cita la "sezione 7.19 della specifica C# 4". : D – Otiel

+0

Per me va tutto bene, ma perché il compilatore non tiene conto anche della disabilitazione "Aritmetica overflow"? Grazie comunque: è stata solo una curiosità a cui sono imbattuto. –

+0

@MarioVernari: Poiché è progettato per modificare il comportamento del tempo di esecuzione, la maggior parte del codice C# è probabilmente costruita con quell'impostazione predefinita, ma la maggior parte degli sviluppatori dovrebbe ancora preoccuparsi se le loro * costanti * eccedono. –

1

Questo non è un comportamento strano, l'intervallo valido per una variabile del tipo di dati byte è 0-255 ma quando si converte HEX 0x1234 valore nel sistema decimale ti ha 4660. Quindi unchecked utilizzato per controllare le operazioni aritmetiche di tipo integrale e le conversioni di controllo di overflow.

È possibile trovare che unchecked viene spesso utilizzato nell'implementazione GetHashCode() che esegue operazioni numeriche per calcolare il codice hash finale.

In sintesi si dovrebbe usare unchecked quando il valore risultato finale delle operazioni integer tipo non è materia, ma troppo pieno potrebbe accadere.

1

È non dovrebbe circondano questo con incontrollato.Deselezionato consente l'assegnazione di tipi di valori pericolosi a un tipo, che può causare overflow.

byte b1 = (byte)i; causerà un overflow o un'eccezione di trasmissione in fase di esecuzione.

byte b2 = (byte)0x1234; non valido perché non è possibile memorizzare valori superiori a 0xFF in un byte.

byte b3 = unchecked((byte)0x1234); inserirà 0x34 o 0x12 (a seconda dell'implementazione CLR) in b3 e l'altro byte si sovrapporrà.

byte b4 = checked((byte)i); è lo stesso di byte b1 = (byte)i;

byte b5 = (byte)(int)0x1234; getteranno 0x1234 ad un int, e quindi provare a gettarlo ai byte. Anche in questo caso, non è possibile convertire 0x1234 in un byte perché è troppo grande.

+0

Bene, hai parzialmente ragione, ma non del tutto. È vero che evitare gli assegni è una pratica pericolosa, ma dovresti anche usarli con un po 'di cervello, IMHO. NON è vero, che il tuo primo incarico causa un'eccezione. Viene lanciato solo se si abilita il "controllo aritmetico" (l'impostazione predefinita è disattivata). Il terzo compito credo sia sbagliato: dovrebbe restituire sempre 0x12. quarto: stesse considerazioni del primo. Quinto: come il secondo. Cheers –

+0

Il terzo restituirà sempre 0x34, non 0x12. E il primo causerà un'eccezione solo se il controllo è abilitato E se il valore è al di fuori dell'intervallo 0-255. – phoog

+0

Grazie per le correzioni ragazzi :) – Polynomial