бокс и распаковка в int и string

Немного запутался бокс и распаковка. По его определению

Упаковка - это неявное преобразование типов значений в ссылочные типы (объект).
Распаковка - это явное преобразование ссылочных типов (объектов) в эквивалентные им типы значений.

лучший пример для описания этого -

int i = 123; object o = i;  // boxing

и

o = 123; i = (int)o;  // unboxing 

Но мой вопрос в том, является ли int типом значения, а строка - ссылочным типом, поэтому

int i = 123; string s = i.ToString();

и

s = "123"; i = (int)s; 

Это пример бокса и распаковки или нет ???


person Gaurav Agrawal    schedule 21.06.2011    source источник
comment
s = "123"; i = (int)s; не компилируется   -  person Piotr Auguscik    schedule 21.06.2011
comment
почему тег OOP? Действительно, C # является объектно-ориентированным языком, но заданный вопрос не имеет отношения к парадигме программирования объектно-ориентированного.   -  person davka    schedule 21.06.2011
comment
@davka: Ну, ToString - это виртуальный метод на object, который затем переопределяется типом Int32, так что это ваше (по общему признанию слабое) соединение ООП.   -  person LukeH    schedule 21.06.2011
comment
@davka Теперь я изменил теги OPs   -  person Isak Savo    schedule 21.06.2011
comment
Сложные концепции, возникающие из-за запутанности языка программирования, поэтому функциональное программирование лучше. Мне нравится C #, но я всегда узнаю что-то новое.   -  person Jaider    schedule 28.02.2015


Ответы (4)


Звонок ToString - это не бокс. Он создает новую строку, которая просто содержит текстовое представление вашего int.

При вызове (object)1 в куче создается новый экземпляр, содержащий int. Но это все еще int. (Вы можете проверить это с помощью o.GetType())

Строку нельзя преобразовать с приведением к int. Таким образом, ваш код не будет компилироваться.

Если вы сначала приведете свою строку к object, ваш код будет компилироваться, но не удастся во время выполнения, поскольку ваш объект не упакован в int. Вы можете распаковать тип значения только в точно правильный тип (или связанный с ним, допускающий значение NULL).

Два примера:

Сломанный:

object o=i.ToString();// o is a string
int i2=(int)o;//Exception, since o is no int

Работающий:

object o=i;// o is a boxed int
int i2=(int)o;//works 
person CodesInChaos    schedule 21.06.2011

 int i = 2;
 string s = i.ToString();

Это НЕ бокс. Это просто вызов метода Int32.ToString(), который возвращает отформатированную строку, представляющую значение int.

 i = (int)s;

Этот код не будет компилироваться, поскольку между System.String и System.Int32 не определено явное преобразование.

Подумайте об этом следующим образом, чтобы понять, что есть, а что нет бокс и распаковка:

  1. Бокс: это когда вы берете тип значения и просто "вставляете" его в ссылочную переменную. Для работы этой операции нет необходимости в какой-либо конкретной логике преобразования. Тип переменной останется прежним, если вы используете GetType().

  2. Распаковка: это прямо противоположная операция. Возьмите тип значения, застрявший в ссылочном объекте, и назначьте его переменной типа значения. Опять же, для работы этой операции нет необходимости в какой-либо логике преобразования конкретного типа.

    Таким образом, если бы (int)s был действительным, это было бы просто явное преобразование, а не операция распаковки, потому что s.GetType() вернет System.String, а не System.Int32.

person InBetween    schedule 21.06.2011
comment
Упакованный тип для типа, допускающего значение NULL, будет базовым типом. И GetType всегда боксы, поэтому результатом GetType для нормального значения, допускающего значение NULL, является базовый тип, тогда как typeof дает вам тип, допускающий значение NULL. - person CodesInChaos; 21.06.2011

Упаковка / распаковка: преобразование типов значений в их объектное представление и наоборот (например, int и object).

Метод ToString (), напротив, представляет собой операцию, которая генерирует новую строку, и не имеет ничего общего с диалоговым окном / приведением / типом.

person codymanix    schedule 21.06.2011

Поздно к вечеринке по этому поводу, но ... Я не люблю просто читать ответы без доказательств. Мне нравится разбираться в проблеме и анализировать возможное решение и проверять, соответствует ли оно моему пониманию. Это копирование и вставка текста из заслуженно признанного превосходного 'CLR via C #' бога Джеффа Рихтера объясняет это:

Несмотря на то, что неупакованные типы значений не имеют указателя на объект типа, вы все равно можете вызывать виртуальные методы (например, Equals, GetHashCode или ToString), унаследованные или переопределенные типом. Если ваш тип значения переопределяет один из этих виртуальных методов, тогда среда CLR может вызывать метод невиртуально, поскольку типы значений неявно запечатаны и не могут иметь никаких типов, производных от них. Кроме того, экземпляр типа значения, используемый для вызова виртуального метода, не упаковывается. Однако, если ваше переопределение виртуального метода вызывает реализацию метода базового типа, то экземпляр типа значения действительно упаковывается при вызове реализации базового типа, так что ссылка на объект кучи передается указателю this в базовый метод. Однако для вызова невиртуального унаследованного метода (например, GetType или MemberwiseClone) всегда требуется, чтобы тип значения был упакован, потому что эти методы определены System.Object, поэтому методы ожидают, что этот аргумент будет указателем, который ссылается на объект в куча.

За эту книгу мистеру Рихтеру следует вручить медаль. Если у вас его нет, получите !! Тогда получишь :)

person MrDev    schedule 30.12.2012
comment
Я не знаю, нужны ли такие слова, как во втором абзаце, так как это единственные три виртуальных метода, которые могут поддерживать типы значений. Самый простой способ объяснить требования для боксов, когда они не переопределяются, - это понять, что каждый метод принимает подразумеваемый параметр this. Если myStruct не отменяет ToString, параметр this будет иметь тип Object; если он переопределит его, параметр this будет иметь тип ref myStruct. Передача переменной myStruct в параметр Object требует бокса; передача его как параметра ref MyStruct - нет. - person supercat; 24.04.2013