Maison >développement back-end >Tutoriel C#.Net >Compilation des connaissances de base en C# Connaissances de base (18) Boxing et unboxing des types valeur (1)
Il est en fait très intéressant d’en savoir plus sur le boxing et le unboxing. Tout d’abord, voyons pourquoi le boxing et le unboxing se produisent ?
Regardez le morceau de code suivant :
class Program { static void Main(string[] args) { ArrayList array = new ArrayList(); Point p;//分配一个 for (int i = 0; i < 5; i++) { p.x = i;//初始化值 p.y = i; array.Add(p);//装箱 } } } public struct Point { public Int32 x; public Int32 y; }
Bouclez 5 fois, en initialisant à chaque fois un champ de type valeur Point puis en le plaçant dans l'ArrayList. Struct est une structure de type valeur, alors qu'est-ce qui est stocké dans ArrayList ? Jetons un autre regard sur la méthode Add d'ArrayList. Vous pouvez voir la méthode Add dans MSDN :
public virtual int Add(Object value),
Vous pouvez voir que le paramètre de Add est de type Object, c'est-à-dire que le paramètre qu'il nécessite est une référence à un objet . Autrement dit, les paramètres ici doivent être des types référence. Quant à ce qu'est un type de référence, il n'est pas nécessaire d'élaborer. Ce n'est rien de plus qu'une référence à un objet sur le tas. Cependant, pour faciliter la compréhension, parlons à nouveau du tas et de la pile.
1. Zone de pile (pile) - automatiquement allouée et libérée par le compilateur, stockant les valeurs des paramètres de fonction, les valeurs des variables locales, etc.
2. Heap - alloué et libéré par le programmeur Si le programmeur ne le libère pas, il peut être recyclé par le système d'exploitation à la fin du programme.
Par exemple :
class Program { static void Main(string[] args) { Int32 n;//这是值类型,存放在栈中,Int32初始值为0 A a;//此时在栈中开辟了空间 a = new A();//真正实例化后的一个对象则保存在堆中。 } } public class A { public A() { } }
Retour à la question ci-dessus, la méthode Add nécessite des paramètres de type référence, que dois-je faire ? Ensuite, vous devez utiliser la boxe. La soi-disant boxe consiste à convertir un type valeur en type référence. Le processus de conversion est le suivant :
1. Allouez de la mémoire dans le tas géré. La quantité de mémoire allouée est la quantité de mémoire requise par les champs individuels du type valeur plus la quantité de mémoire requise par deux membres supplémentaires (le pointeur d'objet de type et l'index de bloc synchronisé) dont disposent tous les objets du tas géré.
2. Copiez le champ de type de valeur dans la mémoire nouvellement allouée.
3. Renvoyez l'adresse de l'objet. À ce stade, l'adresse est une référence à un objet et le type valeur a maintenant été converti en type référence.
De cette façon, dans la méthode Add, une référence à un objet Point encadré est enregistrée. L'objet encadré restera dans le tas jusqu'à ce que le programmeur le gère ou que le système le récupère. À ce stade, la durée de vie du type valeur encadré dépasse la durée de vie du type valeur non encadré.
Avec le boxing ci-dessus, il est naturel de le déballer si vous souhaitez retirer le 0ème élément du tableau :
Point p = (Point)array[0];
Ce que vous devez faire. voici pour obtenir La référence de l'élément 0 de ArrayList est mise dans le type de valeur Point p. Afin d'atteindre cet objectif, comment l'implémenter ? Tout d'abord, obtenez l'adresse de chaque champ Point de l'objet Point encadré. Voilà pour le déballage. Les valeurs contenues dans ces champs sont ensuite copiées du tas vers l'instance de type valeur basée sur la pile. Le déballage est essentiellement le processus d'obtention d'une référence à un type de valeur primitif contenu dans un objet. En fait, la référence pointe vers la partie non boxée de l’instance boxée. Par conséquent, contrairement au boxing, le unboxing ne nécessite pas de copier d’octets en mémoire. Mais il y a un autre point, une opération de copie de champ se produit immédiatement après le déballage.
Par conséquent, le boxing et le unboxing auront un impact négatif sur la vitesse et la consommation de mémoire du programme, alors faites attention au moment où le programme effectuera automatiquement les opérations de boxing/unboxing et essayez d'éviter ces situations lors de l'écriture du code.
Lors du déballage, faites attention aux exceptions suivantes :
1. Si la variable contenant "une référence à l'instance de type valeur encadrée" est nulle, une NullReferenceException sera levée.
2. Si l'objet pointé par la référence n'est pas une instance encadrée du type de valeur attendu, une InvalidCastException sera levée.
Par exemple, l'extrait de code suivant :
Int32 x = 5; Object o = x; Int16 r = (Int16)o;//抛出InvalidCastException异常
Parce qu'il ne peut être converti que dans le type de valeur non boxé d'origine lors du déballage. Modifiez le code ci-dessus en :
Int32 x = 5; Object o = x; //Int16 r = (Int16)o;//抛出InvalidCastException异常 Int16 r = (Int16)(Int32)o;
C'est correct.
Après le déballage, une copie de champ se produira, comme indiqué dans le code suivant :
//会发生字段复制 Point p1; p1.x = 1; p1.y = 2; Object o = p1;//装箱,发生复制 p1 = (Point)o;//拆箱,并将字段从已装箱的实例复制到栈中
Regardez le segment de code suivant :
//要改变已装箱的值 Point p2; p2.x = 10; p2.y = 20; Object o = p2;//装箱 p2 = (Point)o;//拆箱 p2.x = 40;//改变栈中变量的值 o = p2;//再一次装箱,o引用新的已装箱实例
Le but ici est de copier le boxed La valeur x de p2 est modifiée à 40. De cette façon, vous devez déballer une fois, copier le champ dans la pile une fois, modifier la valeur du champ dans la pile, puis effectuer la boxe. besoin d'en créer un nouveau sur le tas. Une instance en boîte de . De cela, nous voyons également l’impact du boxing/unboxing et de la copie sur les performances du programme.
Regardons quelques extraits de code de boxe et de déballage supplémentaires :
//装箱拆箱演示 Int32 v = 5; Object o = v; v = 123; Console.WriteLine(v + "," + (Int32)o);
Il y a trois moments de boxe qui se produisent ici. On peut clairement voir que
Object o = v; v = 123;
Mais dans. La boxe s'est également produite dans Console.WriteLine. Pourquoi ? Parce qu'il y a des paramètres de type chaîne dans WriteLine ici, et que tout le monde sait que la chaîne est un type référence, donc (Int32)o doit être encadré ici. Là encore, le problème de l'utilisation du symbole pour connecter des chaînes dans le programme est expliqué. S'il y a plusieurs types de valeur lors de la connexion, plusieurs opérations de boxing seront effectuées.
Cependant, le code ci-dessus peut être modifié :
//修改后 Console.WriteLine(v.ToString() + "," + o);
De cette façon, il n'y a pas de boxe.
Regardez à nouveau le code suivant :
Int32 v = 5; Object o = v; v = 123; Console.WriteLine(v); v = (Int32)o; Console.WriteLine(v);
Un seul boxing se produit ici, c'est-à-dire Object o = v ici, et Console.WriteLine est surchargé avec int, bool, double, etc., il n’y a donc pas de boxe ici.
Ce qui précède est le contenu des connaissances de base de C# Connaissances de base (18) Boxing et unboxing des types de valeur (1 Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php. cn) !