Подтвердить что ты не робот

Структуры, интерфейсы и бокс

Возможный дубликат:
Безопасно ли для структур создавать интерфейсы?

Возьмите этот код:

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 в этом случае?

4b9b3361

Ответ 1

Да, это так. В принципе, всякий раз, когда вам нужна ссылка, и у вас есть значение типа значения, значение помещается в квадрат.

Здесь ISomeInterface - это интерфейс, который является ссылочным типом. Поэтому значение someVariable всегда является ссылкой, поэтому вновь созданное значение структуры должно быть помещено в коробку.

Ответ 2

Точка Джона - это правда, но в качестве побочного примечания есть одно небольшое исключение из правила; дженерики. Если у вас where T : ISomeInterface, то это ограничение и использует специальный код операции . Это означает, что интерфейс можно использовать без бокса. Например:

public static void Foo<T>(T obj) where T : ISomeInterface {
    obj.Bar(); // Bar defined on ISomeInterface
}

Это не касается бокса, даже для типа значения T. Однако, если (в том же Foo) вы выполните:

ISomeInterface asInterface = obj;
asInterface.Bar();

тогда это поля как и раньше. Ограниченный только применяется непосредственно к T.

Ответ 3

Я добавляю это, надеюсь, пролить немного больше света на ответы, предложенные Джоном и Марком.

Рассмотрим этот не общий метод:

public static void SetToNull(ref ISomeInterface obj) {
    obj = null;
}

Hmm... установка параметра ref в значение null. Это возможно только для ссылочного типа, правильно? (Ну, или для 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, ее можно установить равной нулю, чистой и простой. И это потому, что интерфейсы являются ссылочными типами - следовательно, объявляя объект как интерфейс и присваивая ему полям объектов типа значения, которые имеют значение.

Теперь, с другой стороны, рассмотрим этот гипотетический общий метод:

// 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;
}

Ответ 4

документация MSDN сообщает нам, что structs являются значениями, а не ссылочными типами. Они помещаются в коробку при преобразовании в/из переменной типа object. Но главный вопрос здесь: как насчет переменной типа интерфейса? Так как интерфейс также может быть реализован классом, то это должно быть равносильно преобразованию из значения в ссылочный тип, как уже сказал Джон Скит, поэтому да, будет бокс. Больше обсуждений в блоге msdn.