В .Net:
Часто вы не можете полагаться на тип переменной, которую будет использовать функция, поэтому вам нужно использовать переменную объекта, которая начинается с наименьшего общего знаменателя - в .Net это object
.
Однако object
является классом и хранит его содержимое в качестве ссылки.
List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value
List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int
Хотя оба они содержат одинаковую информацию, второй список больше и медленнее. Каждое значение во втором списке на самом деле является ссылкой object
наint
.
Это называется в штучной упаковке, потому что int
обернут в object
. Когда его отброситьint
распаковывается, оно преобразуется обратно в его значение.
Для типов значений (т.е. всех structs
) это медленно и потенциально занимает гораздо больше места.
Для справочных типов (т.е. всех classes
) это гораздо меньше проблем, так как они все равно хранятся как ссылки.
Еще одна проблема с типом значений в штучной упаковке заключается в том, что не очевидно, что вы имеете дело с блоком, а не со значением. Когда вы сравниваете два, structs
тогда вы сравниваете значения, но когда вы сравниваете два, classes
тогда (по умолчанию) вы сравниваете ссылку - т.е. это один и тот же экземпляр?
Это может сбивать с толку при работе с коробочными типами значений:
int a = 7;
int b = 7;
if(a == b) // Evaluates to true, because a and b have the same value
object c = (object) 7;
object d = (object) 7;
if(c == d) // Evaluates to false, because c and d are different instances
Это легко обойти:
if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals
if(((int) c) == ((int) d)) // Evaluates to true once the values are cast
Однако при работе со значениями в штучной упаковке следует соблюдать осторожность.