Структуры, интерфейсы и бокс
-
27-09-2019 - |
Вопрос
Возможный дубликат:
Безопасно ли структурам реализовывать интерфейсы?
Возьмите этот код:
interface ISomeInterface
{
public int SomeProperty { get; }
}
struct SomeStruct : ISomeInterface
{
int someValue;
public int SomeProperty { get { return someValue; } }
public SomeStruct(int value)
{
someValue = value;
}
}
а затем я делаю это где-то:
ISomeInterface someVariable = new SomeStruct(2);
это SomeStruct
коробочный в данном случае?
Решение
Да это так. В основном, когда вам нужно ссылка И у вас есть только значение типа «Тип значения», значение является в коробке.
Здесь, ISomeInterface
это интерфейс, который является ссылочным типом. Поэтому значение someVariable
Всегда есть ссылка, поэтому вновь созданное значение структуры должно быть в штучной упаковке.
Другие советы
Точка Джона верна, но в качестве побочной записи есть одно небольшое исключение из правила; Дженерики. Если у тебя есть where T : ISomeInterface
, тогда это ограниченный, и использует Специальный код OPCode. Отказ Это означает, что интерфейс может быть использован без заниматься боксом. Например:
public static void Foo<T>(T obj) where T : ISomeInterface {
obj.Bar(); // Bar defined on ISomeInterface
}
Это делает нет включать в себя бокс даже по значению типа T
. Отказ Однако, если (в том же Foo
) вы делаете:
ISomeInterface asInterface = obj;
asInterface.Bar();
Тогда это коробки как раньше. То ограниченный Только применяется напрямую к T
.
Я добавляю это, чтобы, надеюсь, пролить немного больше осветите ответы, предложенные Джоном и Марком.
Рассмотрим этот необщий метод:
public static void SetToNull(ref ISomeInterface obj) {
obj = null;
}
Хм...установка ref
параметр на ноль.Это возможно только для ссылочного типа, верно?(Ну или за Nullable<T>
;но давайте проигнорируем этот случай, чтобы не усложнять задачу.) Таким образом, тот факт, что этот метод компилируется, говорит нам о том, что переменная, объявленная как принадлежащая к некоторому типу интерфейса, должна рассматриваться как ссылочный тип.
Ключевая фраза здесь «объявлена как»:рассмотрите эту попытку вызвать вышеуказанный метод:
var x = new SomeStruct();
// This line does not compile:
// "Cannot convert from ref SomeStruct to ref ISomeInterface" --
// since x is declared to be of type SomeStruct, it cannot be passed
// to a method that wants a parameter of type ref ISomeInterface.
SetToNull(ref x);
Конечно, причина, по которой вы не можете пройти x
в приведенном выше коде, чтобы SetToNull
в том, что x
необходимо будет объявить как ISomeInterface
чтобы ты смог пройти ref x
-- и нет потому что компилятор волшебным образом знает это SetToNull
включает в себя строку obj = null
.Но это лишь подтверждает мою точку зрения:тот obj = null
линия легальна именно потому, что это было бы незаконный передать переменную нет объявлен как ISomeInterface
к методу.
Другими словами, если переменная объявлена как ISomeInterface
, для него можно установить значение null, в чистом виде.И это потому, что интерфейсы являются ссылочными типами - следовательно, объявление объекта как интерфейса и присвоение его объекту типа значения блокирует это значение.
Теперь, с другой стороны, рассмотрим этот гипотетический общий метод:
// This method does not compile:
// "Cannot convert null to type parameter 'T' because it could be
// a non-nullable value type. Consider using 'default(T)' instead." --
// since this method could take a variable declared as, e.g., a SomeStruct,
// the compiler cannot assume a null assignment is legal.
public static void SetToNull<T>(ref T obj) where T : ISomeInterface {
obj = null;
}
То MSDN Документация Рассказывает нам, что структуры являются ценностью, а не ссылочными типами. Они в штучной упаковке при преобразовании в / из переменной типа object
. Отказ Но центральный вопрос здесь: как насчет переменной типа интерфейса? Поскольку интерфейс также может быть реализован классом, то это должно быть равносильно преобразовывать из значения ссылочного типа, как уже сказал Джон Скелет уже, следовательно, да в боксе произойдет. Больше обсуждения в блоге MSDN.