Pergunta

Eu tenho um IDataRecord reader que estou recuperando um decimal a partir da seguinte forma:

decimal d = (decimal)reader[0];

Por alguma razão isso gera uma exceção de elenco inválido dizendo que o "cast especificado não é válido."

Quando eu faço reader[0].GetType() ele me diz que ele é um Int32. Tanto quanto eu sei, isso não deve ser um problema ....

Eu testei isso por esse trecho que funciona muito bem.

int i = 3750;
decimal d = (decimal)i;

Isto deixou-me coçar a cabeça perguntando por que ele não está a unbox o int contido no leitor como um decimal.

Alguém sabe por que isso pode estar ocorrendo? Existe algo sutil que eu estou ausente?

Foi útil?

Solução

Você só pode unbox um tipo de valor para seu tipo original (ea versão anulável desse tipo).

A propósito, este é válido (apenas uma abreviação para a sua versão de duas linhas):

object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion

Para a razão por trás disso ler este Eric blog do Lippert: Representação e Identidade

Pessoalmente, eu categorizar as coisas pela sintaxe elenco em quatro tipos diferentes de operação (todos eles têm diferentes instruções IL):

  1. Boxe (box instrução IL) e unboxing (instrução IL unbox)
  2. Fundição através da hierarquia inhertiance (como dynamic_cast<Type> em C ++, usos castclass instrução IL para verificar a)
  3. conversão entre tipos de primitivas (como static_cast<Type> em C ++, há uma abundância de instruções IL para diferentes tipos de moldes entre os tipos de primitivas)
  4. Chamando os operadores de conversão definidos pelo usuário (no nível de IL são método apenas chamadas para o método op_XXX apropriado).

Outras dicas

Não há nenhum problema em lançar um int para decimal, mas quando você está unboxing um objeto que você tem que usar o tipo exato que o objeto contém.

Para unbox o valor int em um valor decimal, você primeiro unbox-lo como um int, então lançá-lo aos decimal:

decimal d = (decimal)(int)reader[0];

A interface IDataRecord também tem métodos para unboxing o valor:

decimal d = (decimal)reader.GetInt32(0);

Aqui está uma solução simples. Ela cuida de unboxing e depois converter para decimal. bem trabalhou para mim.

decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int

Mehrdad Afshari disse que:

Você só pode unbox um tipo de valor para seu tipo original (eo anulável versão desse tipo).

A primeira coisa a perceber é que há uma diferença entre fundição e unboxing . jerryjvl teve uma excelente observação

Em certo sentido, é uma vergonha que unboxing e lançando sintaticamente olhar idênticas, uma vez que são operações muito diferentes.

Fundição:

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?
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top