Мой вопрос, однако, заключается в том, каким образом компилятор позволяет использовать общее ограничение, чтобы исключить необходимость упаковки типа значения, который явно реализует интерфейс.
Под "компилятором" не ясно, имеете ли вы в виду джиттер или компилятор C #. Компилятор C # делает это, испуская ограниченный префикс для виртуального вызова. Подробности смотрите в документации ограниченного префикса .
Что происходит с закулисной реализацией CLR, которая требует, чтобы тип значения был упакован при доступе к явно реализованному элементу интерфейса
Является ли вызываемый метод явно реализованным элементом интерфейса или нет, это не имеет особого значения. Более общий вопрос заключается в том, почему любой виртуальный вызов требует, чтобы тип значения был упакован?
Традиционно считается, что виртуальный вызов является косвенным вызовом указателя метода в таблице виртуальных функций. Это не совсем то, как вызовы интерфейса работают в CLR, но это разумная ментальная модель для целей этого обсуждения.
Если так будет вызываться виртуальный метод, тогда откуда берется vtable ? Тип значения не содержит vtable. Тип значения просто имеет свое значение в своем хранилище. Бокс создает ссылку на объект, для которого настроена виртуальная таблица, указывающая на все виртуальные методы типа значения. (Опять же, я предупреждаю вас, что это не точно , как работают вызовы интерфейса, но это хороший способ думать об этом.)
Что происходит с общим ограничением, которое снимает это требование?
Джиттер будет генерировать свежий код для каждой конструкции аргумента типа значения универсального метода. Если вы собираетесь генерировать свежий код для каждого отдельного типа значения, вы можете адаптировать этот код к этому конкретному типу значения. Это означает, что вам не нужно создавать виртуальную таблицу, а затем посмотреть, каково ее содержимое! Вы знаете, каким будет содержимое vtable, поэтому просто сгенерируйте код для непосредственного вызова метода.