У меня есть следующий код:
int intNumber1 = 100;
object intNumber2 = 100;
bool areNumberOfTheSameType = intNumber1.GetType() == intNumber2.GetType(); // TRUE
bool areEqual = intNumber1.Equals(intNumber2); // TRUE
long longNumber1 = (long) intNumber1; // OK
long longNumber2 = (long) intNumber2; // InvalidCastException. Why?
Почему не работает второе приведение? Я понимаю, что это может быть потому, что объект не имеет явного приведения к длинному , но если мы посмотрим на его тип во время выполнения, это будет System.Int32
.
Если я использую var
или dynamic
вместо object
, это работает.
Есть мысли?
Приведение из int
в long
интерпретируется как преобразование между двумя типами.
Приведение из объекта
в int
интерпретируется как распаковка упакованного int
.
Это тот же синтаксис, но он говорит о двух разных вещах.
В рабочих случаях ( int
→ long
, объект
(в рамке int
) → int
) , компилятор точно знает, какой код производить. Если бы упакованный int
→ long
работал, компилятор должен был бы каким-то образом выяснить, какое преобразование использовать, но у него недостаточно информации для этого.
См. Также это сообщение в блоге Эрика Липперта .
(Внимание: догадаться)
Int32
имеет оператор преобразования в Int64
, который вызывается при первом приведении. Объект
- нет, поэтому ваше второе приведение пытается привести объект к другому типу, который не является супертипом ( Int64
не наследует Int32
) .
Причина, по которой он работает с var
, очевидна - компилятор просто избавляет вас от ввода int
в этом случае. С динамическим
среда выполнения выполняет все необходимые проверки того, что нужно сделать, в то время как обычно компилятор просто вставляет либо приведение, либо вызывает оператор преобразования.
То, что это не работает из-за того, что это два разных типа приведения (одно преобразование, другое распаковка), уже было указано в ответах здесь. Что может быть полезным дополнением, так это то, что Convert.ToInt64 ()
преобразует все, что является либо встроенным типом, который можно преобразовать в long, либо типом класса, реализующего IConvertible .ToInt64 ()
в длинный. Другими словами, если вы хотите иметь возможность преобразовать объект, содержащий целое число (любого размера) в long, Convert.ToInt64 ()
- это то, что вам нужно. Это дороже, но то, что вы пытаетесь сделать , на дороже, чем литье, и разница незначительна (достаточно большая, чтобы быть расточительной в тех случаях, когда вы знаете, что объект должен быть длинным в коробке).
Вам нужно распаковать до того же типа, который был упакован в коробку.
object intNumber2 = 100L;
// or value in the long type range
// object intNumber2 = 9223372036854775806;
long result = (long)intNumber2;
объект
имеет тип int
. Но он считается объектом (упакованным целым числом), а упакованный тип значения обычно может быть приведен только к его базовому типу (упакованному типу).
Чтобы привести его к другому типу, сначала нужно привести его к базовому типу. Это работает:
long longNumber2 = (long) (int) intNumber2;
Причина, по которой var
работает, заключается в том, что компилятор определяет тип во время компиляции. Это означает, что когда вы используете var
, тип intNumber2
(если вы используете typeof
) будет int
. В то время как при использовании объект
тип будет объект
.
Использование dynamic
— это совершенно другой процесс, и его нельзя сравнивать с var
. Здесь преобразование/приведение происходит во время выполнения с использованием отражения и библиотеки DLR. Он динамически найдет базовый тип, обнаружит, что у него есть оператор преобразования, и использует его.