Что ж, компилятор не может определить в общем случае, какое именно тело метода должно выполняться при вызове метода интерфейса, потому что разные классы могут иметь разные реализации.
Таким образом, когда CLR сталкивается с вызовом интерфейса, он видит при отображении интерфейса вмещающего типа и проверяет, какой конкретный метод он должен вызвать. Это на самом деле ниже, чем IL.
UPD : IMO, это не разница между call
и callvirt
.
Что должен делать CLR при обнаружении callvirt
в типе класса? Получить тип вызываемого, посмотреть на его таблицу виртуальных методов, найти там вызываемый метод и вызвать его.
Что он должен делать, когда обнаруживает callvirt
в типе интерфейса? Ну, в дополнение к предыдущим пунктам следует также проверить такие вещи, как явная реализация интерфейса. Поскольку вы МОЖЕТЕ иметь два метода с одинаковыми сигнатурами - один метод класса, а другой явная реализация интерфейса. Такого просто не существует при работе с типами классов. Я думаю, что здесь главное отличие.
UPD2 : Теперь я уверен, что это так. См. this для подробной информации о реализации.