2012-03-16 21 views
12

Abbiamo un codice che archivia i dati da un database Microsoft Access in un database MS SQL Server. Supponendo che abbiamo un lettore di dati già popolato dalla tabella di Access e stiamo aggiungendo un parametro a un SqlCommand in preparazione per l'inserto, abbiamo un typecast che sta fallendo. Ecco il codice:Perché questo cast da short a int fallisce?

oSqlServerDbCmd_ForInsert.Parameters.AddWithValue("@Duration", 
    (int) oReader["Duration"]); 

il campo dalla oReader è in realtà un intero Access, che è una breve in C#. Se lanciamo un corto qui non ci sono problemi. Tuttavia, se eseguiamo il cast su un int, il codice genera una InvalidCastException. Potrei leggere erroneamente questo da MSDN documentation:

"Esiste una conversione implicita predefinita da breve a int, long, float, double o decimal."

... ma sembra che questo dovrebbe funzionare (il mio ragionamento è che, se viene definita una conversione implicita, perché un typecast esplicito non funziona?). Mi rendo conto che il cast non è nemmeno necessario perché AddWithValue accetta un oggetto, quindi abbiamo effettivamente rimosso il cast dal nostro codice, ma mi piacerebbe vedere una spiegazione del perché questo cast stava fallendo nel caso in cui ci imbattessimo in qualcosa del genere in il futuro.

+1

Buon articolo di Eric Lippert su questo http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx –

+0

questa non è una risposta alla tua domanda, ma sembra che il parametro '@ Duration' dovrebbe avere a tipo di dati numerici, nel qual caso non si desidera utilizzare un valore stringa nella chiamata 'AddWithValue'. – phoog

+0

@phoog Ho modificato il codice per rimuovere quella conversione in quanto è una distrazione da ciò a cui questa domanda è finita. La risposta breve è che la conversione della stringa era nel codice quando l'abbiamo ereditata. Dal momento che funzionava fino a quando non abbiamo modificato il tipo di dati nel DB di origine, non avremmo avuto motivo di indagare sul codice. Una volta rotto e scavato abbiamo visto che la conversione delle stringhe non era necessaria (anche se non è problematica, credeteci o no). –

risposta

18

Quello che hai tra le mani è un'istanza di unboxing. In particolare, quando si seleziona unbox, è possibile annullare l'accesso solo al tipo di valore originariamente inserito; se quel tipo è A e si sta annullando la casella su B, , non importa se esiste una conversione implicita da A a B (l'annullamento non riuscirà ancora).

Vedere Eric Lippert's classic blog post sull'argomento per una spiegazione implicita.

+0

+1 Mi dimentico sempre di questo. 'oggetto o = (breve) 10; int i = (int) o; 'fallisce. –

+1

Ah questo ha senso. Quindi, se fossi stato scritturato per la prima volta, avrei potuto scriverlo come int senza problemi? –

+1

@ awilson53: Esattamente. – Jon

5

Bisogna lanciare al tipo molto specifico in quanto si sta Unboxing - il problema è che oReader["Duration"] restituisce un object esempio:

short myShort = 42; 
object o = myShort; 
int myInt = (int)o; //fails 

avrà successo se si esegue il cast di nuovo a breve, poi a int:

(int) (short) oReader["Duration"] 
+0

Grazie per il feedback, +1 ... entrambi avete risposto alla mia domanda, quindi dovrò andare con il primo motore. –

Problemi correlati