Имеют ли интерфейсные переменные семантику типа значения или ссылочного типа? - PullRequest
9 голосов
/ 17 декабря 2011

Имеют ли переменные интерфейса семантику типа значения или ссылочного типа?

Интерфейсы реализованы по типам, и эти типы являются либо типами значений, либо ссылочными типами. Очевидно, что и int, и string реализуют IComparable, и int является типом значения, а string является ссылочным типом. Но что по этому поводу:

IComparable x = 42;
IComparable y = "Hello, World!";

(Вопрос, на который я пытался ответить, предположительно был удален, поскольку в нем спрашивалось, хранятся ли интерфейсы в стеке или в куче, и, как мы все должны знать, более конструктивно думать о различиях между значениями и ссылочными типами в термины их семантики, а не их реализации. Для обсуждения см. Эрика Липперта. Стек - это деталь реализации .)

Ответы [ 4 ]

13 голосов
/ 17 декабря 2011

Обычно, согласно существующим ответам, это ссылочный тип и требует бокса;Хотя есть исключение (не всегда?).В универсальном методе с ограничением where это может быть и :

void Foo<T>(T obj) where T : ISomeInterface {
    obj.SomeMethod();
}

Это операция с ограничением , и она не упаковывается в даже если , это тип значения.Это достигается с помощью constrained.Вместо этого JIT выполняет операцию как виртуальный вызов для ссылочных типов и статический вызов для типов значений.Нет бокса.

5 голосов
/ 17 декабря 2011

Это о понимании упаковки и распаковки типов.В вашем примере int присваивается при назначении, а ссылка на этот «ящик» или объект - это то, что присваивается x.Тип значения int определяется как структура, которая реализует IComparable.Однако после того, как вы воспользуетесь этой интерфейсной ссылкой для ссылки на тип значения int, она будет упакована в кучи.Вот как это работает на практике.Тот факт, что использование ссылки на интерфейс приводит к определению бокса, определяет семантику этого типа ссылки.

MSDN: упаковка и распаковка

3 голосов
/ 17 декабря 2011

Переменная или поле, тип которого IComparable, является переменной или полем ссылочного типа, независимо от типа значения, назначенного этому полю.Это означает, что x в примере кода заключено в коробку.

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

    [TestMethod, ExpectedException(typeof(InvalidCastException))]
    public void BoxingTest()
    {
        IComparable i = 42;
        byte b = (byte)i;      //exception: not allowed to unbox an int to any type other than int
        Assert.AreEqual(42, b);
        Assert.Fail();
    }

EDIT

Кроме того, спецификация C # специально определяет ссылочный тип как включающий типы классов, типы интерфейсов, типы массивов и типы делегатов.

EDIT2

Как отмечает Марк Гравелл в своем ответе, универсальный тип с ограничением интерфейса - это другой случай.Это не вызывает бокс.

2 голосов
/ 17 декабря 2011

Переменные типа интерфейса всегда будут иметь неизменяемую семантику, изменяемую ссылочную семантику или семантику «странного» (что-то отличное от обычной ссылочной семантики или семантики значений).Если variable1 и variable2 оба объявлены как один и тот же тип интерфейса, один выполняет variable2 = variable1, и никогда больше не записывает ни в одну из переменных, экземпляр, на который указывает variable1, всегда будет неотличим от экземпляра, на который указываютvariable2 (поскольку это будет тот же экземпляр).

Универсальные типы с интерфейсными ограничениями могут иметь неизменяемую семантику, изменяемую ссылочную семантику или "причудливую" семантику, но также могут иметь семантику изменяемых значений.Это может быть опасно, если интерфейс не задокументирован как имеющий изменяемую семантику значений.К сожалению, нет никакого способа ограничить интерфейс иметь либо неизменяемую семантику, либо семантику изменяемого значения (это означает, что после variable2 = variable1 не должно быть возможности изменить variable1, написав variable2, и наоборот).Можно добавить ограничение "struct" вместе с ограничением интерфейса, но это исключит классы, которые имеют неизменную семантику, не исключая структуры, которые имеют ссылочную семантику.

...