Подтвердить что ты не робот

Странное поведение. Нельзя лить объект (int) длинным

У меня есть следующий код:

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, он работает.

Любые мысли?

4b9b3361

Ответ 1

Передача от int до long интерпретируется как преобразование между двумя типами.

Передача от object до int интерпретируется как unboxing boxed int.

Это тот же синтаксис, но он говорит две разные вещи.

В рабочих случаях (intlong, object (в коробке int) → int) компилятор точно знает, какой код должен быть создан. Если бы работать с коробкой intlong, компилятор должен каким-то образом определить, какое преобразование использовать, но для этого недостаточно информации.

См. также это сообщение в блоге от Эрика Липперта.

Ответ 2

object имеет тип int. Но он считал объект (который представляет собой коробку int), а тип значения в виде бокса обычно может быть передан только его базовому типу (тип, который помещен в коробку).

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

long longNumber2 = (long) (int) intNumber2;

Причина, по которой работает var, заключается в том, что компилятор указывает тип во время компиляции. Это означает, что при использовании var тип intNumber2 (если вы используете typeof) будет int. Если вы используете object, тип будет object.

Использование dynamic - это совершенно другой процесс и не может сравниться с var. Здесь преобразование/кастинг происходит во время выполнения, используя отражение и библиотеку DLR. Он будет динамически находить базовый тип, обнаруживает, что он имеет оператор преобразования и использует его.

Ответ 3

(Предостережение: Угадай)

Int32 имеет оператор преобразования в Int64, который является тем, что вызывается при первом приведении. Object не делает этого, поэтому ваш второй актер пытается передать объект другому типу, который не является супертипом (Int64 не наследует Int32).

Причина, по которой он работает с var, очевиден - компилятор просто спасает вас от ввода int в этом случае. С помощью dynamic среда выполнения выполняет все необходимые проверки того, что должно быть выполнено, в то время как обычно компилятор просто вставляет либо бросок, либо вызывает оператор преобразования.

Ответ 4

Это не работает из-за того, что в ответах здесь уже указано два разных типа бросков (одно преобразование, другое unboxing). Что может быть полезным дополнением, заключается в том, что Convert.ToInt64() преобразует все, что является встроенным типом, который может быть преобразован в long или тип класса, который реализует IConvertible.ToInt64(), в длинный. Другими словами, если вы хотите, чтобы объект с целым числом (любого размера) был длинным, Convert.ToInt64() - это путь. Это дороже, но то, что вы пытаетесь сделать , более дорогое, чем литье, и разница небрежна (достаточно большая, чтобы быть расточительной в тех случаях, когда вы знаете, что объект должен быть коротким).

Ответ 5

Вам нужно распаковать тот же тип, который был помещен в коробку.

object intNumber2 = 100L;
// or value in the long type range
// object intNumber2 = 9223372036854775806;

long result = (long)intNumber2;