Упаковка и распаковывание: когда это подходит?

Таким образом, я понимаю, каковы упаковка и распаковывание. Когда это подходится в реальном коде, или в том, какие примеры это - проблема? Я не могу предположить делать что-то вроде этого пример:

int i = 123;
object o = i;           // Boxing
int j = (int)o;     // Unboxing

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

14
задан Jon Seigel 22 December 2009 в 21:05
поделиться

7 ответов

Это много в настоящее время проблема не так важна, как до дженериков. Теперь, например, мы можем использовать:

List<int> x = new List<int>();
x.Add(10);
int y = x[0];

Никакой упаковки или распаковки не требуется.

Раньше у нас было бы:

ArrayList x = new ArrayList();
x.Add(10); // Boxing
int y = (int) x[0]; // Unboxing

Это был мой самый распространенный опыт упаковки и распаковки. , по крайней мере.

Я думаю, что без дженериков я ' Я, наверное, сказал бы, что рефлексия - самая частая причина бокса в проектах, над которыми я работал. API отражения всегда используют «объект» для таких вещей, как возвращаемое значение для метода - потому что у них нет другого способа узнать, что использовать.

Другая причина, которая может вас поймать, если вы не знаете об этом, - это если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы этого не знаете.

Мы не знаем об этом, если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы об этом не знаете.

Мы не знаем об этом, если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы об этом не знаете.

34
ответ дан 1 December 2019 в 06:12
поделиться

Упаковка (по моему опыту) обычно происходит в следующих случаях:

  • Тип значения передается методу, который принимает аргумент типа Object .
  • Тип значения добавляется в неуниверсальную коллекцию (например, ArrayList ).

В других случаях вы можете увидеть упаковку и распаковку, когда вы используете отражение, поскольку API отражения платформы .NET активно использует Объект .

8
ответ дан 1 December 2019 в 06:12
поделиться

Упаковка / распаковка происходит, когда куда-то передается тип значения (например, struct, int, long), который принимает ссылочный тип, например объект .

Это возникает, когда вы явно создаете метод, который принимает параметры типа object, которому будут передаваться типы значений. Это также возникает, когда вы используете старые неуниверсальные коллекции для хранения типов значений (обычно примитивов).

Вы также увидите, что бокс происходит, когда вы используете String.Format () и передаете ему примитивы . Это связано с тем, что String.Format () принимает объект params [], что приводит к упаковке дополнительных параметров в вызове.

Использование отражения для вызова методов также может привести к упаковке / распаковке, поскольку API отражения не имеют другого выбора, кроме как вернуть объект , поскольку реальный тип неизвестен во время компиляции (и API отражения не могут быть универсальными).

Новые общие коллекции не приводят к упаковке / unboxing, поэтому они предпочтительнее старых коллекций по этой причине (например, ArrayList, Hashtable и т. д.). Не говоря уже о том, что они безопасны для типов.

Вы можете избежать проблем с упаковкой, изменив методы, которые принимают объекты как общие. Например:

public void string Decorate( object a ) // passing a value type results in boxing
{
   return a.ToString() + " Some other value";
}

vs:

public void string Decorate<T>( T a )
{
   return a.ToString() + " some other value";
}
5
ответ дан 1 December 2019 в 06:12
поделиться

Вот действительно неприятный вопрос :)

SqlCommand cmd = <a command that returns a scalar value stored as int>;

// This code works very well.
int result = (int)cmd.ExecuteScalar();

// This code will throw an exception.
uint result = (uint)cmd.ExecuteScalar();

Второе выполнение завершается неудачно, потому что оно пытается распаковать Int32 в UInt32, что невозможно. Так что сначала вам нужно распаковать, а затем отлить.

uint result = (uint)(int)cmd.ExecuteScalar();
3
ответ дан 1 December 2019 в 06:12
поделиться

Это происходит все время, когда люди не знают, каковы последствия, просто не заботятся или иногда нельзя не принять бокс как меньший уровень.

Строго типизированные данные будут box / unbox практически все время, когда вы обращаетесь к свойству-значению. Кроме того, использование типа значения в качестве ссылки на интерфейс также поместит его в рамку. Или получение делегата из метода экземпляра значимого типа. (Целевой объект делегата имеет тип Object)

1
ответ дан 1 December 2019 в 06:12
поделиться

С появлением строго типизированных списков и словарей, использующих универсальные шаблоны с C # 2.0 (Visual Studio 2005), я думаю, что важность сохранения в памяти упаковки / распаковки была удивительно минимизирована. Добавьте к этому типы, допускающие значение NULL ( int? и т. Д.) И используя оператор объединения NULL ( ?? ), и это действительно не должно вызывать особого беспокойства и, скорее всего, не увидеть его в коде, отличном от 1.1 Framework или более ранней версии.

0
ответ дан 1 December 2019 в 06:12
поделиться

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

Конечно, есть случаи, когда это актуально. Включение дженериков во фреймворк 2.0 исключило из практики множество распространенных случаев бокса.

1
ответ дан 1 December 2019 в 06:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: