2012-01-07 8 views
8

Ho difficoltà a capirlo. Si consideri il seguente esempio:C# - Problemi con box/unboxing/intro typecasting. Non capisco

protected void Page_Load(object sender, EventArgs e) 
{ 
    // No surprise that this works 
    Int16 firstTest = Convert.ToInt16(0); 
    int firstTest2 = (int)firstTest; 

    // This also works 
    object secondTest = 0; 
    int secondTest2 = (int)secondTest; 

    // But this fails! 
    object thirdTest = Convert.ToInt16(0); 
    int thirdtest2 = (int)thirdTest; // It blows up on this line. 
} 

L'errore specifico che ottengo in fase di esecuzione è Specified cast is not valid. Se Controllo immediato (int)thirdTest in Visual Studio, ottengo un valore Cannot unbox 'thirdTest' as a 'int'.

Che diavolo sta succedendo qui?

+1

Int16 è in realtà un breve. Quindi penso che puoi sostituire 'Int16 firstTest = Convert.ToInt16 (0);' con 'Int16 firstTest = 0s;' –

risposta

12

Unboxing controlla il tipo esatto come spiegato nello documentation.

unboxing è una conversione esplicita dall'oggetto tipo di un tipo di valore o da un tipo di interfaccia per un tipo di valore che implementa l'interfaccia . Un'operazione unboxing composto da:

  • Leggere l'istanza di oggetto per assicurarsi che è un valore scatolata dato tipo di valore.

  • Copia del valore dall'istanza nella variabile del tipo valore.

Come si può vedere il primo passo è quello di verificare che l'istanza di oggetto corrisponde al tipo di destinazione.

citare anche dalla documentazione:

Per l'unboxing di tipi di valore per avere successo in fase di esecuzione, l'elemento essendo unboxed deve essere un riferimento a un oggetto che è stato creato in precedenza da boxe un'istanza di quel tipo di valore. Il tentativo di annullare la cancellazione di null causa una eccezione NullReferenceException. Il tentativo di rimuovere un riferimento da un riferimento a un tipo di valore incompatibile causa una InvalidCastException.

Quindi, per correggere questo errore assicurarsi che il tipo di partite prima di tentare di Unbox:

object thirdTest = Convert.ToInt16(0); 
short thirdtest2 = (short)thirdTest; 
+2

Oppure disiscrivilo con il tipo corretto, quindi esegui il cast sul tipo desiderato. 'int thirdtest2 = (int) (short) thirdTest;' –

9

Cosa sta succedendo è esattamente quello che dice.

Nel primo caso, si dispone di un breve, unboxed, che si esegue quindi tipograficamente ad un int. Questa è una conversione valida che il compilatore sa come fare, quindi funziona.

Nel secondo caso, si dispone di un int, in scatola, che si stanno assegnando a un int. Questo è un semplice unboxing di un intero, che è anche valido, quindi funziona.

Nel terzo caso, si dispone di un breve, in scatola, che si sta tentando di annullare una casella in una variabile che non è un breve. Questa non è un'operazione valida: non puoi farlo in un solo passaggio.Questo non è un problema raro, sia: se si sta utilizzando, per esempio, un SqlDataReader che contiene una colonna SMALLINT, non si può fare:

int x = (int)rdr["SmallIntColumn"]; 

Uno dei seguenti dovrebbe funzionare nel terzo esempio:

object thirdTest = Convert.ToInt16(0); 
    int thirdTest2 = Convert.ToInt32(thirdTest); 
    int thirdTest3 = (int)(short)thirdTest; 
4

Int16 è un modo elegante per scrivere short; non c'è boxing/unboxing in corso, solo la conversione CLR semplice tra interi a 16 bit e 32 bit.

Il secondo caso inserisce e cancella lo stesso tipo, che è consentito: il tipo di valore int viene incapsulato in un object e viene scartato.

Il terzo caso tenta di unboxing ad un diverso tipo (int anziché short) non consentito.