Почему я не могу распаковать значение int как десятичное?

StackOverflow https://stackoverflow.com/questions/1085097

  •  23-08-2019
  •  | 
  •  

Вопрос

У меня есть IDataRecord reader из которого я извлекаю десятичное число следующим образом:

decimal d = (decimal)reader[0];

По какой-то причине это выдает недопустимое исключение приведения, в котором говорится, что "Указанное приведение недопустимо".

Когда я делаю reader[0].GetType() это говорит мне, что это Int32.Насколько я знаю, это не должно быть проблемой....

Я проверил это с помощью этого фрагмента, который работает просто отлично.

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

Это заставило меня почесать в затылке, задаваясь вопросом, почему не удается распаковать значение int, содержащееся в reader, в виде десятичного числа.

Кто-нибудь знает, почему это может происходить?Есть ли что-то тонкое, чего мне не хватает?

Это было полезно?

Решение

Вы можете только распаковать тип значения до его исходного типа (и обнуляемую версию этого типа).

Кстати, это действительно (просто сокращение для вашей двухстрочной версии):

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

О причине, стоящей за этим, прочтите это Запись в блоге Эрика Липперта:Представительство и Идентичность

Лично я классифицирую действия, выполняемые с помощью синтаксиса приведения, на четыре различных типа операций (все они имеют разные инструкции IL).:

  1. Бокс (box Инструкция IL) и распаковка коробки (unbox IL instruction)
  2. Приведение через иерархию наследования (например dynamic_cast<Type> в C ++ используется castclass (инструкция для проверки)
  3. Приведение между примитивными типами (например static_cast<Type> в C ++ существует множество инструкций IL для различных типов приведения между примитивными типами)
  4. Вызов определяемых пользователем операторов преобразования (на уровне IL это просто вызовы методов к соответствующему op_XXX способ).

Другие советы

Нет никаких проблем в том, чтобы разыграть int Для decimal, но когда вы распаковываете объект, вы должны использовать точный тип, который содержит объект.

Чтобы распаковать int значение в decimal значение, вы сначала распаковываете его как int, затем приводите к десятичному:

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

Интерфейс IDataRecord также имеет методы для распаковки значения:

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

Вот простое решение.Он заботится о распаковке и последующем преобразовании в десятичное число.У меня это прекрасно сработало.

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

Это сказал Мехрдад Афшари:

Вы можете только разархивировать тип значения до его исходного типа (и nullable версия этого типа).

Главное, что нужно осознать , это то , что есть разница между кастингом и распаковкой коробки.у джерриджвла было отличное замечание

В некотором смысле обидно, что синтаксически распаковка и приведение выглядят идентично, поскольку это очень разные операции.

Кастинг:

int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK

Упаковка / Распаковка:

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?
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top