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