Maison développement back-end Tutoriel C#.Net Compilation de connaissances sur la boxe et le déballage C#

Compilation de connaissances sur la boxe et le déballage C#

Jan 24, 2017 pm 02:25 PM

1. La boxe et le déballage sont des concepts abstraits
2. La boxe convertit les types de valeur en types de référence

Le déballage convertit les types de référence en types de valeur

À l'aide des fonctions de boxe et de déballage, les types valeur peuvent être liés aux types référence en permettant à n'importe quelle valeur du type valeur d'être convertie vers et depuis le type Objet

Par exemple :

int val = 100; 
object obj = val; 
Console.WriteLine (“对象的值 = {0}", obj);
Copier après la connexion

Il s'agit d'un processus de boxe, qui est le processus de conversion des types valeur en types référence

int val = 100; 
object obj = val; 
int num = (int) obj; 
Console.WriteLine ("num: {0}", num);
Copier après la connexion

Il s'agit d'un processus de déballage, qui est le processus de conversion des types valeur en types référence, puis par types référence Le processus de conversion en une valeur type

Remarque : seuls les objets encadrés peuvent être déballés
3. Dans .NET, les types de données sont divisés en types de valeur et en types de référence (non équivalents aux pointeurs), L'allocation de mémoire est donc divisée en deux De différentes manières, l'un est la pile et l'autre est le tas (remarque : il s'agit d'un tas géré)
Les types de valeur ne seront alloués que sur la pile.
Les types de référence allouent de la mémoire et du tas géré.
Le tas géré correspond au garbage collection.

4 : Qu’est-ce que le boxing/unboxing ?
Boxing : utilisé pour stocker les types de valeur dans le tas de garbage collection. La boxe est une conversion implicite d’un type valeur en type objet ou en tout type d’interface implémenté par le type valeur.
Unboxing : une conversion explicite d'un type d'objet en un type valeur ou d'un type d'interface en un type valeur qui implémente l'interface.

5 : Pourquoi un emballage est-il nécessaire ? (Pourquoi convertir les types valeur en types référence ?)
L'un des scénarios les plus courants consiste à appeler une méthode avec un paramètre de type Object. L'Object peut prendre en charge n'importe quel type pour une utilisation universelle. Lorsque vous devez transmettre un type valeur (tel que Int32), la boxe est requise.
Une autre utilisation est un conteneur non générique, également pour garantir l'universalité, le type d'élément est défini comme Objet. Par conséquent, lors de l’ajout de données de type valeur à un conteneur, le boxing est requis.

6 : Opérations internes de boxing/unboxing

Boxing
Alloue une instance d'objet dans le tas pour un type de valeur et copie la valeur dans un nouvel objet. Suivez trois étapes.

Mémoire de tas gérée nouvellement allouée (la taille est la taille de l'instance de type valeur plus un pointeur de table de méthodes et un SyncBlockIndex).
Copiez les champs d'instance du type valeur dans la mémoire nouvellement allouée.
Renvoie l'adresse de l'objet nouvellement alloué dans le tas géré. Cette adresse est une référence à l'objet.
Certaines personnes le comprennent ainsi : si Int32 est encadré, l'adresse renvoyée pointe vers un Int32. Je pense qu'il n'est pas impossible de le comprendre de cette façon, mais cela pose des problèmes. Premièrement, il n'est pas complet et, deuxièmement, pointer vers Int32 ne révèle pas son essence (dans le tas géré).

Unboxing
Vérifie l'instance d'objet pour s'assurer qu'il s'agit d'une valeur encadrée du type de valeur donné. Copie la valeur de l'instance dans une variable de type valeur.
Selon certains livres, le déballage n'obtient que le pointeur vers la partie type valeur de l'objet de référence, et la copie du contenu est le déclencheur de l'instruction d'affectation. Je ne pense pas que cela ait de l'importance. La chose la plus importante est de vérifier la nature de l'instance d'objet. Les types de unboxing et de boxing doivent correspondre. À ce stade, au niveau de la couche IL, je ne vois pas le principe, c'est peut-être qu'une méthode comme GetType est appelée. . Supprimez le type pour la correspondance (car une correspondance stricte est requise).

7 : L'impact du boxing/unboxing sur l'efficacité d'exécution

Évidemment, cela ressort du principe que lors du boxing, un tout nouvel objet de référence est généré, ce qui prendra du temps, c'est-à-dire, ce qui entraîne une efficacité réduite.
Que faire ?
Tout d’abord, la boxe doit être évitée autant que possible.
Par exemple, les deux situations de l'exemple 2 ci-dessus peuvent être évitées. Dans le premier cas, cela peut être évité en surchargeant la fonction. Le deuxième cas peut être évité grâce aux génériques.
Bien sûr, rien n'est absolu. Supposons que le code que vous souhaitez modifier soit un assembly tiers et que vous ne puissiez pas le modifier, vous ne pouvez alors que le mettre en boîte.
Pour l'optimisation du code de boxing/unboxing, puisque le boxing et le unboxing sont implicites en C#, la méthode fondamentale est d'analyser le code, et la manière la plus directe d'analyser est de comprendre la structure principale Voir le code IL décompilé.

Par exemple : il peut y avoir une boxe redondante dans le corps de la boucle, vous pouvez simplement utiliser une boxe avancée pour l'optimisation.

8 : Meilleure compréhension de l'emballage/unboxing

L'emballage/unboxing n'est pas aussi simple et clair que mentionné ci-dessus

Par exemple : lors de l'emballage, changez Pour référencer un objet, il y aura un pointeur de table de méthode supplémentaire. A quoi sert-il ?

Nous pouvons explorer davantage avec des exemples.

Par exemple :

Struct A : ICloneable
{
public Int32 x;
public override String ToString() {
return String.Format(”{0}”,x);
}
public object Clone() {
return MemberwiseClone();
}
}
static void main() 
{ 
A a; 
a.x = 100; 
Console.WriteLine(a.ToString()); 
Console.WriteLine(a.GetType()); 
A a2 = (A)a.Clone(); 
ICloneable c = a2; 
Ojbect o = c.Clone(); 
}
Copier après la connexion

a.ToString()。编译器发现A重写了ToString方法,会直接调用ToString的指令。因为A是值类型,编译器不会出现多态行为。因此,直接调用,不装箱。(注:ToString是A的基类System.ValueType的方法) 
a.GetType(),GetType是继承于System.ValueType的方法,要调用它,需要一个方法表指针,于是a将被装箱,从而生成方法表指针,调用基类的System.ValueType。(补一句,所有的值类型都是继承于System.ValueType的)。 
a.Clone(),因为A实现了Clone方法,所以无需装箱。 
ICloneable转型:当a2为转为接口类型时,必须装箱,因为接口是一种引用类型。 
c.Clone()。无需装箱,在托管堆中对上一步已装箱的对象进行调用。 
附:其实上面的基于一个根本的原理,因为未装箱的值类型没有方法表指针,所以,不能通过值类型来调用其上继承的虚方法。另外,接口类型是一个引用类型。对此,我的理解,该方法表指针类似C++的虚函数表指针,它是用来实现引用对象的多态机制的重要依据。

9:如何更改已装箱的对象

对于已装箱的对象,因为无法直接调用其指定方法,所以必须先拆箱,再调用方法,但再次拆箱,会生成新的栈实例,而无法修改装箱对象。有点晕吧,感觉在说绕口令。还是举个例子来说:(在上例中追加change方法) 

public void Change(Int32 x) { 
this.x = x; 
}
Copier après la connexion

调用: 

A a = new A(); 
a.x = 100; 
Object o = a; //装箱成o,下面,想改变o的值
((A)o).Change(200); //改掉了吗?没改掉
Copier après la connexion
没改掉的原因是o在拆箱时,生成的是临时的栈实例A,所以,改动是基于临时A的,并未改到装箱对象。

(附:在托管C++中,允许直接取加拆箱时第一步得到的实例引用,而直接更改,但C#不行。) 
那该如何是好? 
嗯,通过接口方式,可以达到相同的效果。 
实现如下: 

interface IChange { 
void Change(Int32 x); 
} 
struct A : IChange { 
… 
}
Copier après la connexion

调用:

((IChange)o).Change(200);//改掉了吗?改掉了
Copier après la connexion

为啥现在可以改?


在将o转型为IChange时,这里不会进行再次装箱,当然更不会拆箱,因为o已经是引用类型,再因为它是IChange类型,所以可以直接调用Change,于是,更改的也就是已装箱对象中的字段了,达到期望的效果。

10、将值类型转换为引用类型,需要进行装箱操作(boxing):

首先从托管堆中为新生成的引用对象分配内存
然后将值类型的数据拷贝到刚刚分配的内存中
返回托管堆中新分配对象的地址
可以看出,进行一次装箱要进行分配内存和拷贝数据这两项比较影响性能的操作。

将引用类型转换为值类型,需要进行拆箱操作(unboxing):

首先获取托管堆中属于值类型那部分字段的地址,这一步是严格意义上的拆箱。
将引用对象中的值拷贝到位于线程堆栈上的值类型实例中。
经过这2步,可以认为是同boxing是互反操作。严格意义上的拆箱,并不影响性能,但伴随这之后的拷贝数据的操作就会同boxing操作中一样影响性能。

11、

NET的所有类型都是由基类System.Object继承过来的,包括最常用的基础类型:int, byte, short,bool等等,就是说所有的事物都是对象。

如果申明这些类型得时候都在堆(HEAP)中分配内存,会造成极低的效率!(个中原因以及关于堆和栈得区别会在另一篇里单独得说说!)
.NET如何解决这个问题得了?正是通过将类型分成值型(value)和引用型(regerencetype),

C#中定义的值类型和引用类型

值类型:原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举(enum)、结构(struct)
引用类型:类、数组、接口、委托、字符串等
值型就是在栈中分配内存,在申明的同时就初始化,以确保数据不为NULL;
引用型是在堆中分配内存,初始化为null,引用型是需要GARBAGE COLLECTION来回收内存的,值型不用,超出了作用范围,系统就会自动释放!
下面就来说装箱和拆箱的定义!
装箱就是隐式的将一个值型转换为引用型对象。比如:

int i=0;
Syste.Object obj=i;
Copier après la connexion

这个过程就是装箱!就是将i装箱!
拆箱就是将一个引用型对象转换成任意值型!比如:

int i=0;
System.Object obj=i;
int j=(int)obj;
Copier après la connexion

这个过程前2句是将i装箱,后一句是将obj拆箱!

更多c#装箱和拆箱知识整理相关文章请关注PHP中文网!


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

Repo: Comment relancer ses coéquipiers
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
4 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

.NET Deep Dive: Mastering Asynchronous Programming, Linq et EF Core .NET Deep Dive: Mastering Asynchronous Programming, Linq et EF Core Mar 31, 2025 pm 04:07 PM

Les concepts de base de la programmation asynchrone .NET, LINQ et EFCORE sont: 1. La programmation asynchrone améliore la réactivité de l'application par asynchronisation et attente; 2. LINQ simplifie la requête de données par le biais de la syntaxe unifiée; 3. EfCore simplifie les opérations de base de données via ORM.

Quel est le rôle de char dans les chaînes C Quel est le rôle de char dans les chaînes C Apr 03, 2025 pm 03:15 PM

En C, le type de char est utilisé dans les chaînes: 1. Stockez un seul caractère; 2. Utilisez un tableau pour représenter une chaîne et se terminer avec un terminateur nul; 3. Faire fonctionner via une fonction de fonctionnement de chaîne; 4. Lisez ou sortant une chaîne du clavier.

Comment gérer les caractères spéciaux dans la langue C Comment gérer les caractères spéciaux dans la langue C Apr 03, 2025 pm 03:18 PM

Dans le langage C, les caractères spéciaux sont traités à travers des séquences d'échappement, telles que: \ n représente les pauses de ligne. \ t signifie le caractère d'onglet. Utilisez des séquences d'échappement ou des constantes de caractères pour représenter des caractères spéciaux, tels que char c = '\ n'. Notez que l'arrière-plan doit être échappé deux fois. Différentes plates-formes et compilateurs peuvent avoir différentes séquences d'échappement, veuillez consulter la documentation.

Comment utiliser divers symboles dans le langage C Comment utiliser divers symboles dans le langage C Apr 03, 2025 pm 04:48 PM

Les méthodes d'utilisation des symboles dans la couverture du langage C Couverture arithmétique, l'affectation, les conditions, la logique, les opérateurs de bits, etc. Les opérateurs arithmétiques sont utilisés pour les opérations mathématiques de base, les opérateurs d'affectation sont utilisés pour les opérations et les opérations de la soustraction, la multiplication et les opérations de division, les opérations BIT sont utilisé pointeurs nuls, marqueurs de fin de fichier et valeurs non nucères.

C # .NET avancé: concurrence, parallélisme et multithreading expliqué C # .NET avancé: concurrence, parallélisme et multithreading expliqué Apr 03, 2025 am 12:01 AM

C # .NET fournit des outils puissants pour la programmation simultanée, parallèle et multithread. 1) Utilisez la classe de threads pour créer et gérer des threads, 2) La classe de tâches fournit une abstraction plus avancée, en utilisant des pools de threads pour améliorer l'utilisation des ressources, 3) Implémentez l'informatique parallèle via Parallel.ForEach, 4) Async / Await et Task.

Comment utiliser Char Array dans la langue C Comment utiliser Char Array dans la langue C Apr 03, 2025 pm 03:24 PM

Le Array Char stocke des séquences de caractères en C et est déclaré Char Array_name [Taille]. L'élément d'accès est passé par l'opérateur d'indice, et l'élément se termine par le terminateur nul «\ 0», qui représente le point final de la chaîne. Le langage C fournit une variété de fonctions de manipulation de cordes, telles que strlen (), strcpy (), strcat () et strcmp ().

Comment convertir le charbon dans la langue C Comment convertir le charbon dans la langue C Apr 03, 2025 pm 03:21 PM

Dans le langage C, la conversion de type char peut être directement convertie en un autre type par: Casting: Utilisation de caractères de casting. Conversion de type automatique: Lorsqu'un type de données peut accueillir un autre type de valeur, le compilateur le convertit automatiquement.

Évitez les erreurs causées par défaut dans les instructions du commutateur C Évitez les erreurs causées par défaut dans les instructions du commutateur C Apr 03, 2025 pm 03:45 PM

Une stratégie pour éviter les erreurs causées par défaut dans les instructions de commutateur C: utilisez des énumérations au lieu des constantes, limitant la valeur de l'instruction de cas à un membre valide de l'énumération. Utilisez Fallthrough dans la dernière instruction de cas pour permettre au programme de continuer à exécuter le code suivant. Pour les instructions de commutation sans tomber, ajoutez toujours une instruction par défaut pour la gestion des erreurs ou fournissez un comportement par défaut.

See all articles