2015-12-28 3 views
11

У меня есть два вопроса:Почему типы значений наследуются от ссылочных типов?

  1. Мы знаем все виды происходят из Object, который является ссылочным типом. Мой вопрос: почему int - это значение тип - наследуется от ссылочного типа Object? Это возможно?

  2. Если int происходит от Object, почему мы должны боксировать при переходе int на функцию, которая ожидает object в качестве параметра? Обычно со ссылками, когда вам нужно передать объект производного типа в качестве параметра функции, ожидающего объект базового типа, вам не нужно делать ничего дополнительного. Почему ящик здесь?

Для меня эта ситуация кажется проблемой в том, как была разработана эта иерархия типов.

PS. Я нашел this связанный вопрос, но ответ там не дает реалистичного понимания - просто абстрактно говорит о коробках.

+0

'все типы происходят от Object' __isn't всегда верно. –

+2

принятый ответ на [этот другой вопрос] (http://stackoverflow.com/questions/1682231/how-do-valuetypes-derive-from-object-referencetype-and-still-be-valuetypes) гораздо более уместен –

+1

[Не все происходит от объекта] (http://i1.blogs.msdn.com/b/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx) –

ответ

2

Мы знаем, что все типы происходят от объекта. который является ссылочным типом. Мой вопрос почему int - который является типом значения - наследуется от ссылки type Object? Это возможно?

System.Int32 происходит от System.ValueType, также как и все структуры на C#. Эта цепочка наследования разрешена компилятором, который является тем же самым механизмом, который запрещает вам наследование в любом другом struct. Общее время выполнения (CLR) общего языка имеет специальную семантику для типов, которые производятся от System.ValueType. System.ValueType сам по себе не является типом значения, это ссылочный тип, который формирует базовый класс для всех структур. Хотя эта иерархия наследования существует, она не должна гарантировать ничего о том, как объекты будут выложены в памяти.

Почему нам нужно поле при передаче функции int, которая ожидает объект как параметр? Обычно со ссылками, когда вам нужно передать объект производного типа в качестве параметра для функции ожидающего объекта базового типа, вам не нужно ничего делать. Почему ящик здесь?

Потому что, хотя любой struct в конечном счете происходит от object, он фактически трактуется по-разному по времени выполнения. Все структуры рассматриваются как блок данных, у них нет указателя таблицы методов или индекса блока синхронизации, который имеет каждый ссылочный тип в .NET. Вот почему любой тип значения, который передается методу, принимающему object, должен быть помещен в бокс, поскольку дополнительные данные должны быть добавлены к нему, чтобы фактически стать полностью квалифицированным типом object. Типы значений не только помещаются в бокс, когда они передаются как object, но и в коробке, например, когда вы вызываете метод, который был добавлен в ваш struct в результате реализации интерфейса. Этот тип значения должен быть помещен в бокс, чтобы получить фактический указатель таблицы метода к методу, который необходимо вызвать.

Вы можете увидеть это с небольшим примером:

void Main() 
{ 
    IFoo m = new M(); 
    m.X(); 
} 

public struct M : IFoo 
{ 
    public void X() { } 
} 

public interface IFoo 
{ 
    void X(); 
} 

даст следующий IL (составитель в режиме выпуска):

IL_0000: ldloca.s 00 
IL_0002: initobj  UserQuery.M 
IL_0008: ldloc.0  
IL_0009: box   UserQuery.M 
IL_000E: callvirt UserQuery+IFoo.X 
IL_0013: ret   
+0

@ downvoter Объясните нижний предел. –

+0

У всех нас есть. Каждый пост здесь. –

+0

@ Хенк Я не говорил, что нисходящие голоса нужно объяснять. Я любезно спросил, кто бы ни зашел, если он действительно добр, объясняет, что не так с ответ, чтобы я мог его улучшить. Я не обязал этого делать это. –

-1

Типы значений либо стек выделяется или выделяются встроенным в структуры. Типы ссылок выделены в виде кучи. Оба типа ссылок и значений производятся из конечного базового класса Object. В тех случаях, когда тип значения должен действовать как объект, оболочка, которая делает тип значения похожим на ссылочный объект, выделяется в куче, и значение типа значения копируется в него. Оболочка помечена так, что система знает, что она содержит тип значения. Этот процесс известен как бокс, а обратный процесс называется распаковкой. Бокс и unboxing позволяют любому типу рассматриваться как объект.

3

Мы должны быть осторожны, чтобы не смешивать концепции здесь.

Во-первых, есть подтипирование. int - это подтип object. Подтип в основном означает, что контракт гарантирован супертипом (например, «Существует метод ToString, который возвращает подходящее представление строки.«) также гарантируется для подтипа.

Тогда есть Наследование в C#. В C#, наследование

  1. создает подтип, гарантируя, что интерфейс обеспечивается супертип также доступен в подтипе и

  2. обеспечивает реализацию по умолчанию, то есть, если вы не отменяете метод, вы получаете реализацию супертипа. Это в основном удобная функция.

(реализация интерфейса в C# будет примером для другого механизма подтипировании, который обеспечивает 1, но не 2.)

Это в основном все. Ни подтипирование, ни наследование не гарантируют макеты памяти, семантику значения/ссылочного типа и т. Д. Концепции ортогональны.


"Но это не так," вы могли бы сказать. «Часть договора object является« ссылочной формой семантики ». Здесь бокс необходим. Он имитирует семантику ссылочного типа всякий раз, когда тип времени компиляции типа значения является ссылочным типом (то есть object, ValueType или интерфейсом).

+0

«Но это неправильно», можно сказать. «Часть объектного контракта - это« семантика ссылочного типа »». Именно здесь необходим бокс. Он моделирует семантику ссылочного типа всякий раз, когда тип типа компиляции типа значения является ссылочным типом (т.е. объектом, ValueType или интерфейсом). »- ну, но тогда обычно вам не нужно ничего делать при передаче объекта производного типа как для функции, которая ожидает ссылки на базовый тип, но здесь вам нужен бокс. Так что это странная ситуация до некоторой степени –

+0

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

Смежные вопросы