Почему для вызова некоторых функций класса Object в экземпляре примитивного типа нужен бокс?
Я обнаружил, что если я запускаю следующие строки кода.
int i = 7;
i.GetHashCode(); //where GetHashCode() is the derived
//function from System.Object
Нет бокса, но если я назову i.GetType()
(другая производная функция из System.Object
) вместо GetHashCode()
, для вызова GetType()
потребуется бокс, почему его нельзя вызвать GetType()
на экземпляр примитивного типа напрямую, без бокса, в то время как его можно вызвать GetHashCode()
без бокса?
Ответы
Ответ 1
Ключ здесь в том, что GetType()
не является виртуальным и не может быть переопределен. Поскольку структура эффективно sealed
, методы не могут быть переопределены больше, чем структура, поэтому среда выполнения и компилятор могут рассматривать методы struct , которые были переопределены как статические вызовы.
Если вы пишете структуру (редко), вы должны переопределить все методы, такие как ToString()
, Equals()
, GetHashCode()
именно по этой причине. Если вы этого не сделаете, он должен быть в коробке. Однако GetType()
не может переопределяться, поэтому необходим бокс.
Это фактически приводит к некоторым нечетным ребрам с Nullable<T>
и боксом, так как пустые Nullable<T>
поля для null
, поэтому:
int i = obj.GetHashCode(); // fine
Type t = obj.GetType(); // boom
Ответ 2
Я думаю, причина в том, что GetHashCode реализован непосредственно на System.Int32, вы вызываете System.Int32:: GetHashCode(). Не нужно вводить поле, если вы вызываете известную функцию-член в типе значения.
Ответ 3
Кажется очень близким к Как ValueType.GetType() может определить тип структуры?
Также связан путаница GetType и TypeOf