Dans .Net:
Souvent, vous ne pouvez pas vous fier au type de variable qu'une fonction consommera, vous devez donc utiliser une variable objet qui s'étend du plus petit dénominateur commun - dans .Net c'est object
.
Cependant object
est une classe et stocke son contenu comme référence.
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
Bien que les deux contiennent les mêmes informations, la deuxième liste est plus longue et plus lente. Chaque valeur de la deuxième liste est en fait une référence à un object
qui contient le int
.
Ceci est appelé boxed car le int
est enveloppé par le object
. Quand il int
est renvoyé, il est déballé - reconverti à sa valeur.
Pour les types valeur (c'est-à-dire tous structs
), cela est lent et utilise potentiellement beaucoup plus d'espace.
Pour les types de référence (c'est-à-dire tous classes
), c'est bien moins un problème, car ils sont de toute façon stockés comme référence.
Un autre problème avec un type de valeur encadré est qu'il n'est pas évident que vous traitez avec la boîte plutôt qu'avec la valeur. Lorsque vous comparez deux, structs
vous comparez des valeurs, mais lorsque vous comparez deux, vous comparez classes
(par défaut) la référence - c'est-à-dire que ce sont les mêmes instances?
Cela peut être déroutant lorsqu'il s'agit de types de valeur encadrés:
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
Il est facile de contourner:
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
Cependant, c'est une autre chose à laquelle il faut faire attention lorsqu'il s'agit de valeurs encadrées.