Таким образом, я понимаю, каковы упаковка и распаковывание. Когда это подходится в реальном коде, или в том, какие примеры это - проблема? Я не могу предположить делать что-то вроде этого пример:
int i = 123;
object o = i; // Boxing
int j = (int)o; // Unboxing
... но это почти наверняка чрезвычайно упрощено, и я, возможно, даже сделал упаковку/распаковывание, не зная это прежде.
Это много в настоящее время проблема не так важна, как до дженериков. Теперь, например, мы можем использовать:
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 отражения всегда используют «объект» для таких вещей, как возвращаемое значение для метода - потому что у них нет другого способа узнать, что использовать.
Другая причина, которая может вас поймать, если вы не знаете об этом, - это если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы этого не знаете.
Мы не знаем об этом, если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы об этом не знаете. Мы не знаем об этом, если вы используете тип значения, который реализует интерфейс, и передаете это значение другому методу, который имеет тип интерфейса в качестве параметра. Опять же, дженерики уменьшают эту проблему, но это может стать неприятным сюрпризом, если вы об этом не знаете.Упаковка (по моему опыту) обычно происходит в следующих случаях:
Object
. ArrayList
). В других случаях вы можете увидеть упаковку и распаковку, когда вы используете отражение, поскольку API отражения платформы .NET активно использует Объект
.
Упаковка / распаковка происходит, когда куда-то передается тип значения (например, 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";
}
Вот действительно неприятный вопрос :)
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();
Это происходит все время, когда люди не знают, каковы последствия, просто не заботятся или иногда нельзя не принять бокс как меньший уровень.
Строго типизированные данные будут box / unbox практически все время, когда вы обращаетесь к свойству-значению. Кроме того, использование типа значения в качестве ссылки на интерфейс также поместит его в рамку. Или получение делегата из метода экземпляра значимого типа. (Целевой объект делегата имеет тип Object)
С появлением строго типизированных списков и словарей, использующих универсальные шаблоны с C # 2.0 (Visual Studio 2005), я думаю, что важность сохранения в памяти упаковки / распаковки была удивительно минимизирована. Добавьте к этому типы, допускающие значение NULL ( int?
и т. Д.) И используя оператор объединения NULL ( ??
), и это действительно не должно вызывать особого беспокойства и, скорее всего, не увидеть его в коде, отличном от 1.1 Framework или более ранней версии.
Упаковка и распаковка действительно перемещаются от типа значения к типу ссылки. Так что думайте об этом как о перемещении из стека в кучу и обратно.
Конечно, есть случаи, когда это актуально. Включение дженериков во фреймворк 2.0 исключило из практики множество распространенных случаев бокса.