Я думаю, что ответ в спецификации C # того, как интерфейсы могут быть обработаны. Из спецификации:
Есть несколько видов
переменные в C #, включая поля,
элементы массива, локальные переменные и
параметры. Переменные представляют
места хранения и каждая переменная
имеет тип, который определяет, что
значения могут быть сохранены в переменной,
как показано в следующей таблице.
В приведенной ниже таблице говорится об интерфейсе
Пустая ссылка, ссылка на экземпляр типа класса, который
реализует этот тип интерфейса, или
ссылка на упакованное значение значения
тип, который реализует этот интерфейс
тип
В нем явно сказано, что это будет коробочное значение типа значения. Компилятор просто подчиняется спецификации
** Редактировать **
Для добавления дополнительной информации на основе комментария. Компилятор может переписать его, если он имеет тот же эффект, но поскольку происходит боксирование, вы создаете копию типа значения, не имеющего того же типа значения. Из спецификации снова:
Преобразование бокса подразумевает создание
копия значения в штучной упаковке. Это
отличается от преобразования
ссылка-тип для типа объекта, в
значение которого продолжает ссылаться
тот же экземпляр и просто
рассматривается как менее производный тип
объект.
Это означает, что он должен заниматься боксом каждый раз, иначе вы получите непоследовательное поведение. Простой пример этого можно показать, выполнив следующие действия с предоставленной программой:
public interface I { void F(); }
public struct C : I {
public int i;
public void F() { i++; }
public int GetI() { return i; }
}
class P
{
static void Main(string[] args)
{
C x = new C();
I ix = (I)x;
ix.F();
ix.F();
x.F();
((I)x).F();
Console.WriteLine(x.GetI());
Console.WriteLine(((C)ix).GetI());
Console.ReadLine();
}
}
Я добавил внутренний элемент в структуру C
, который увеличивается на 1 каждый раз, когда F()
вызывается для этого объекта. Это позволяет нам увидеть, что происходит с данными нашего типа значения. Если на x
не был выполнен бокс, вы ожидаете, что программа выписает 4 для обоих вызовов на GetI()
, поскольку мы вызываем F()
четыре раза. Однако фактический результат, который мы получаем, равен 1 и 2. Причина в том, что бокс сделал копию.
Это показывает нам, что есть разница между тем, если мы поместим значение в коробку, и если мы не будем указывать значение