Почему для вызова некоторых функций класса 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(). Не нужно вводить поле, если вы вызываете известную функцию-член в типе значения.