Почему вызов явной реализации интерфейса для типа значения вызывает его упаковку?

Мой вопрос в некоторой степени связан с этим: Как универсальное ограничение предотвратить упаковку типа значения с неявно реализованным интерфейсом? , но отличается, потому что для этого не должно быть никаких ограничений, потому что он совсем не общий.

У меня есть код

interface I { void F(); }
struct C : I { void I.F() {} }
static class P {
    static void Main()
    {    
        C x;
        ((I)x).F();
    }
}

Основной метод компилируется на это:

IL_0000:  ldloc.0
IL_0001:  box        C
IL_0006:  callvirt   instance void I::F()
IL_000b:  ret

Почему он не компилируется с этим?

IL_0000:  ldloca.s   V_0
IL_0002:  call       instance void C::I.F()
IL_0007:  ret

Я понимаю, почему вам нужна таблица методов для выполнения виртуального вызова, но в этом случае вам не нужно делать виртуальный вызов. Если интерфейс реализован нормально, он не выполняет виртуальный вызов.

Также связано: Почему явные реализации интерфейса являются частными? - существующие ответы на этот вопрос неадекватно объясняют, почему методы помечены как частные в метаданных (а не просто имеют непригодные для использования имена). Но даже это не полностью объясняет, почему он упакован, поскольку он все еще упаковывается при вызове изнутри C.

15
задан Community 23 May 2017 в 12:33
поделиться