Я отвечу только на вопросы 2 и 4, потому что, похоже, что на остальные уже есть удовлетворительный ответ.
Сначала давайте посмотрим на этот код из вашего вопроса:
int i = 10;
object x = i;
Теперь, для меня это звучит так, как будто вы обдумываете это Да, это правда, что тип System.Object
не содержит ни одного члена, который представлял бы int
, который был помещен здесь. Но это не делает этот случай чем-то отличным от другого кода, который вы выложили, и вы, кажется, прекрасно понимаете:
Person p = new Customer();
p.Name = "Water Cooler v2";
В этом случае класс Customer
является производным от класса Person
. Существуют поля, методы и т. Д., Принадлежащие Customer
, которые не видны из контекста Person
, но Customer
- это a Person
. Точно так же, System.Int32
(что то же самое, что и int
, как указывали другие) происходит от System.Object
. Просто есть операции, которые вы можете выполнить на int
, которые не видны из контекста object
- например, выполнение сложения и т. Д. Но int
- это an object
.
Итак, ответ на вопрос "что на самом деле помещается в кучу?" (кстати, куча, являющаяся деталью реализации CLR) на самом деле довольно проста: туда ставится int
.
Теперь, если я могу немного откатиться назад, я хочу ответить на этот вопрос:
Но мы не можем new
структуру, верно?
На самом деле, это неточно. Что делает ключевое слово new
? Похоже, вы думаете в терминах C ++ и предполагаете, что если тип размещен в стеке (опять же, обратите внимание на детали реализации), то использование ключевого слова new
не имеет смысла. Но в C # new
в основном означает, что вы вызываете конструктор типа. И типы значений (структуры) имеют конструкторы, как и ссылочные типы (классы); так что да, эта строка:
IComparable x = 10;
фактически совпадает с:
IComparable x = new System.Int32(10); // if System.Int32 had a public
// parameterized constructor
// (which it doesn't, probably
// because that would just
// confuse people)
Теперь позвольте мне задать вам вопрос: в чем важная разница между типами значений и ссылочными типами в .NET? Если ваш ответ включает какое-либо из слов «стек», «куча» или «выделенный», то, скорее всего, вы сосредоточены на неправильной вещи. Какое это имеет значение для нас, разработчиков, для размещения объектов (помимо подробностей, связанных с настройкой производительности)? На мой взгляд, важное различие заключается в том, что типы значений передаются по значению (копируются) в вызовах методов . Честно, вот и все. Вот что важно.
Когда вы смотрите таким образом, большая загадка бокса / распаковки на самом деле не так таинственна. Давайте посмотрим на этот код еще раз:
int i = 10;
object x = i;
Мы говорим, что в приведенном выше коде мы "упаковываем" целое число i
в объекте x
. Но что подразумевается под этим термином «бокс»? Это то же самое, что поместить значения в кучу? Как это может быть, если выделение кучи и стека является неопределенной деталью реализации?
Помните, что я говорил о типах значений. Важно, чтобы int
был типом значения: когда вы передаете int
методу, вы действительно передаете копию. Это поведение всех типов значений, аналогичное тому, как говорят все типы, производные от System.ValueType
. Но обратите внимание, что System.Object
не происходит от System.ValueType
. Это наоборот. object
является ссылочным типом.
Итак, "бокс" на самом деле означает, что вы берете объект, который в силу его типа всегда передается по значению, и приводите его к базовому типу (object
) который передается по ссылке *.
Если я могу предложить несколько глупую аналогию: предположим, что вы идете в какой-то странный тематический парк, где применяются следующие правила:
- Все люди по умолчанию ездят на колесе обозрения.
- Жители Нью-Йорка, в частности, вместо этого едут на карусели.
Перед тем, как войти в парк, вы заполняете небольшую форму, классифицирующую себя. После подачи этой формы вы получите красный браслет, если вы из Нью-Йорка, или синий браслет.
Что если вы из Нью-Йорка, но хотите прокатиться на колесе обозрения? Все просто: вместо того, чтобы заполнять вашу классификацию как «житель Нью-Йорка», вы просто пишете «Персона». Бинго, они дают вам синий браслет, и вы в.
Ключевое различие, которое следует здесь сделать, заключается в том, что объекты могут делать и как они обрабатываются . Как я уже говорил несколько раз, System.Int32
происходит от System.Object
, и поэтому вы можете привести int
к object
так же легко, как вы можете привести объект любого типа к типу. из которого это происходит. Все это ограничивает то, что вы можете делать с этим объектом, потому что доступны только методы, поля и т. Д. Базового класса. Ничего особенного там нет. Но , бросая int
на object
, вы меняете способ обработки . Точно так же, как приведение себя в примере тематического парка к «Персоне» - что-то менее конкретное, чем то, что вы есть на самом деле, «житель Нью-Йорка», или другими словами базовый тип - вы изменили способ вас лечили.
Имеет ли это смысл?
* Утверждение, что ссылочные типы «передаются по ссылке», возможно, не является строго точным утверждением и вызвало много недоразумений для многих разработчиков (более точное утверждение может быть «ссылки на ссылочных типов передаются значение"); для подробного обсуждения этой темы вам нужно поискать в другом месте.