Я напишу этот вопрос прямо Джеффри Рихтеру, но в последний раз он не ответил мне:), поэтому я постараюсь получить ответ с вашей помощью здесь, ребята:)
В книге "CLR via С#", 3-е издание, стр .108, Джеффри пишет:
void M3() {
Employee e;
e = new Manager();
year = e.GetYearsEmployed();
...
}
Следующая строка кода в вызовах M3 Невиртуальный экземпляр сотрудников Метод GetYearsEmployed. При звонке метод невиртуального экземпляра, JIT компилятор находит объект типа, который соответствует типу переменная, используемая для выполнения вызова. В этом случае переменная e является определяемый как Сотрудник. ( Если Тип сотрудника не определял метод вызывается JIT-компилятор вниз по иерархии классов к объекту ищет этот метод. Он может делать это потому, что каждый объект типа имеет поле в нем, которое ссылается на его базу тип; эта информация не показана в цифры.) Затем компилятор JIT находит запись в объектах типа таблица методов, которая ссылается на метод вызывается, JIT-метод (если необходимо), а затем вызывает JITted код.
Когда я впервые прочитал это, я подумал, что было бы неэффективно ходить по иерархии классов, ища метод во время JIT-ting. Легко найти этот метод уже на стадии компиляции. Но я верил Джеффри. Я разместил эту информацию на другом форуме, и другой парень подтвердил мои сомнения в том, что это странно и будет неэффективным и что, похоже, это неправильная информация.
И действительно, если вы ищете соответствующий 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();
Результирующий IL:
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 во время выполнения.
Не ошибся ли Джеффри Рихтер? Или я что-то не понимаю?