Почему я не могу распаковать int как десятичное число?
У меня есть IDataRecord reader
, что я получаю десятичное число из следующего:
decimal d = (decimal)reader[0];
По какой-то причине это порождает недопустимое исключение броска, говорящее, что "Указанный приведение недействительно".
Когда я делаю reader[0].GetType()
, он сообщает мне, что это Int32. Насколько я знаю, это не должно быть проблемой....
Я тестировал этот фрагмент, который отлично работает.
int i = 3750;
decimal d = (decimal)i;
Это заставило меня почесывать мою голову, задаваясь вопросом, почему она не может распаковать int, содержащуюся в читателе, как десятичную.
Кто-нибудь знает, почему это может произойти? Есть ли что-то тонкое, что мне не хватает?
Ответы
Ответ 1
Вы можете только удалить тип значения в его исходный тип (и версию с нулевым значением этого типа).
Кстати, это действительно (просто сокращение для вашей двухстрочной версии):
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it a widening conversion
По этой причине читайте эту запись в блоге Eric Lippert: представление и идентификация
Лично я классифицирую вещи, сделанные синтаксисом cast, на четыре разных типа операции (все они имеют разные инструкции IL):
- Бокс (
box
IL-инструкция) и распаковка (unbox
IL-команда)
- Прохождение через иерархию inhertiance (например,
dynamic_cast<Type>
в С++ использует проверку castclass
IL)
- Листинг между примитивными типами (например,
static_cast<Type>
в С++, существует множество инструкций IL для разных типов отбрасываний между примитивными типами)
- Вызов пользовательских операторов преобразования (на уровне IL они просто вызовы методов для соответствующего метода
op_XXX
).
Ответ 2
Нет проблем при создании int
до decimal
, но при распаковке объекта вы должны использовать точный тип, который содержит этот объект.
Чтобы удалить значение int
в значение decimal
, вы сначала распакуете его как int, а затем отбросите его до десятичной:
decimal d = (decimal)(int)reader[0];
Интерфейс IDataRecord также имеет методы для распаковки значения:
decimal d = (decimal)reader.GetInt32(0);
Ответ 3
Вот простое решение. Он заботится о распаковке, а затем опускается до десятичной. Работала хорошо для меня.
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
Ответ 4
Мехрдад Афшари сказал это:
Вы можете только удалить тип значения в его исходный тип (и значение NULL версия этого типа).
Чтобы понять, что существует разница между литьем и распаковкой. jerryjvl имел отличное замечание
В некотором смысле это позор, что синтаксически выглядят распаковывание и кастинг идентичны, так как они очень разные операции.
Кастинг:
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?