Perché non posso unboxing un int come decimale?
Domanda
Ho un IDataRecord reader
che sto recuperando un decimale da come segue:
decimal d = (decimal)reader[0];
Per qualche motivo questo genera un'eccezione getto valida dicendo che il "Cast specificato non è valido."
Quando faccio reader[0].GetType()
mi dice che si tratta di un Int32. Per quanto ne so, questo non dovrebbe essere un problema ....
Ho testato questo fuori da questo frammento di codice che funziona bene.
int i = 3750;
decimal d = (decimal)i;
Questo mi ha lasciato graffiare la mia testa chiedendosi il motivo per cui non riesce a unboxing INT contenuta nel lettore come un decimale.
Qualcuno sa perché questo potrebbe essere che si verificano? C'è qualcosa di sottile che mi manca?
Soluzione
È possibile unboxing solo un tipo di valore al suo tipo originale (e la versione nullable di quel tipo).
A proposito, questo è valido (solo una scorciatoia per la versione a due righe):
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion
Per la ragione alla base di questo leggere questo Eric blog di Lippert: Rappresentazione e identità
Personalmente, ho classificare le cose fatte dalla sintassi fusione in quattro diversi tipi di operazioni (tutti hanno diverse istruzioni IL):
- Pugilato (
box
istruzioni IL) e unboxing (unbox
istruzioni IL) - Casting attraverso la gerarchia inhertiance (come
dynamic_cast<Type>
in C ++, utilizzacastclass
istruzioni IL verificare) - Casting tra i tipi primitivi (come
static_cast<Type>
in C ++, ci sono un sacco di istruzioni IL per diversi tipi di calchi tra tipi primitivi) - Calling operatori di conversione definiti dall'utente (a livello IL sono solo le chiamate di metodo al metodo
op_XXX
appropriato).
Altri suggerimenti
Non v'è alcun problema in che esprimono un int
a decimal
, ma quando si sono unboxing di un oggetto è necessario utilizzare il tipo esatto che l'oggetto contiene.
Per unboxing il valore int
in un valore decimal
, in primo luogo Unbox come un int, poi gettarlo ai decimali:
decimal d = (decimal)(int)reader[0];
L'interfaccia IDataRecord ha anche metodi per unboxing del valore:
decimal d = (decimal)reader.GetInt32(0);
Ecco una soluzione semplice. Si prende cura di unboxing e poi colata a decimale. Ha lavorato bene per me.
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
Mehrdad Afshari ha detto:
È possibile solo unboxing un tipo di valore al suo tipo originale (e la nullable versione di quel tipo).
La cosa da capire è che v'è una differenza tra casting e unboxing . jerryjvl ha una chiara osservazione
In un certo senso è un peccato che unboxing e lanciando un'occhiata sintatticamente identici, poiché sono operazioni molto diverse.
Casting:
int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK
Boxe / unboxing:
object i = 3750; // Boxes an int ("3750" is similar to "(int)3750")
decimal d = (decimal)i; // Unboxes the boxed int into a decimal > KO, can only unbox it into a int or int?