Я бы написал этот вопрос напрямую Джеффри Рихтеру, но в прошлый раз он не ответил мне :) так что я постараюсь получить ответ с вашей помощью здесь, ребята :)
В книге "CLR via C #", 3-е издание, на стр.108, Джеффри пишет:
void M3() {
Employee e;
e = new Manager();
year = e.GetYearsEmployed();
...
}
следующая строка кода в вызовах M3 Невиртуальный экземпляр сотрудника GetYearsEmployed. При звонке невиртуальный метод экземпляра, JIT компилятор находит объект типа, который соответствует типу переменная, используемая для вызова. В этом случае переменная e равна определяется как Сотрудник. ( Если Тип сотрудника не определяет метод при вызове JIT-компилятор проходит вниз по иерархии классов к объекту ищу этот метод. Это может сделать это потому, что каждый объект типа имеет поле в нем, которое относится к его базе тип; эта информация не отображается в цифры.) Затем JIT-компилятор находит запись в типе объекта таблица методов, которая относится к методу вызывается, JIT выполняет метод (если необходимо), а затем вызывает JITted code.
Когда я прочитал это в первый раз, я подумал, что было бы неэффективно ходить по иерархии классов в поисках метода во время JIT-тинга. Метод легко найти уже на этапе компиляции. Но я верил Джеффри. Я разместил эту информацию на другом форуме, и другой парень подтвердил мои сомнения, что это странно и будет неэффективным, и что, похоже, это неверная информация.
И действительно, если вы посмотрите соответствующий код IL в декомпиляторе, таком как ILDasm или Reflector (я проверил оба) вы увидите, что в IL есть инструкция callvirt, вызывающая метод из базового класса, поэтому JIT не нужно смотреть, в каком классе находится метод во время выполнения:
public class EmployeeBase
{
public int GetYearsEmployed() { return 1; }
}
public class Employee : EmployeeBase
{
public void SomeOtherMethod() { }
}
public class Manager : Employee
{
public void GenProgressReport() { }
}
...
Employee e;
e = new Manager();
int years = e.GetYearsEmployed();
Результат ИЛ это:
L_0000: nop
L_0001: newobj instance void TestProj.Form1/Manager::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: callvirt instance int32 TestProj.Form1/EmployeeBase::GetYearsEmployed()
Понимаете? Компилятор уже обнаружил, что метод находится не в классе Employee, но в классе EmployeeBase и отправил правильный вызов. Но, по словам Рихтера, JIT должна была бы выяснить, что метод на самом деле находится в классе EmployeeBase во время выполнения.
Ошибся ли Джеффри Рихтер? Или я чего-то не понимаю?