W sieci:
Często nie można polegać na tym, jaki typ zmiennej będzie zużywać funkcja, więc trzeba użyć zmiennej obiektu, która rozciąga się od najniższego wspólnego mianownika - to jest .Net object
.
Jednak object
jest to klasa i przechowuje swoją zawartość jako odniesienie.
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
Chociaż oba zawierają te same informacje, druga lista jest dłuższa i wolniejsza. Każda wartość na drugiej liście jest w rzeczywistości odwołaniem do elementu object
zawierającego rozszerzenie int
.
Nazywa się to pudełkiem, ponieważ int
jest opakowane przez object
. Kiedy int
zostanie odrzucony, zostanie rozpakowany - przekonwertowany z powrotem na swoją wartość.
W przypadku typów wartości (tj. Wszystkich structs
) jest to powolne i potencjalnie zajmuje dużo więcej miejsca.
W przypadku typów referencyjnych (tj. Wszystkich classes
) jest to znacznie mniejszy problem, ponieważ i tak są one przechowywane jako referencje.
Kolejnym problemem związanym z typem wartości w pudełku jest to, że nie jest oczywiste, że masz do czynienia z pudełkiem, a nie z wartością. Kiedy porównujesz dwie structs
, porównujesz wartości, ale kiedy porównujesz dwie, classes
wtedy (domyślnie) porównujesz odniesienie - tj. Czy to jest ta sama instancja?
Może to być mylące, gdy mamy do czynienia z opakowanymi typami wartości:
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
Łatwo jest obejść:
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
Jednak w przypadku wartości pudełkowych należy zachować ostrożność.