Question

  

Il existe des cas où une instance d'un   type de valeur doit être traité comme un   instance d'un type de référence. Pour   Des situations comme celle-ci, un type de valeur   instance peut être converti en un   instance de type de référence à travers un   processus appelé boxe. Quand une valeur   l'instance de type est encadrée, le stockage est   alloué sur le tas et la   La valeur de l'instance est copiée dans cette   espace. Une référence à ce stockage est   placé sur la pile. La valeur en boîte   est un objet, un type de référence qui   contient le contenu de la valeur   type instance.

     

Présentation du système de types commun de .NET

Dans Wikipedia , il existe un exemple pour Java. Mais en C #, dans certains cas, il faudrait encadrer un type de valeur. Ou une question meilleure / similaire serait: pourquoi voudrait-on stocker un type de valeur sur le tas (encadré) plutôt que sur la pile?

Était-ce utile?

La solution

En général, vous voudrez généralement éviter de mettre en boîte vos types de valeur.

Cependant, il existe de rares occasions où cela est utile. Si vous devez cibler le framework 1.1, par exemple, vous n’avez pas accès aux collections génériques. Toute utilisation des collections dans .NET 1.1 nécessiterait de traiter votre type de valeur en tant que System.Object, ce qui entraînerait la boxing / unboxing.

Il existe encore des cas pour que cela soit utile dans .NET 2.0+. Chaque fois que vous souhaitez tirer parti du fait que tous les types, y compris les types de valeur, peuvent être traités directement en tant qu'objet, vous devrez peut-être utiliser boxing / unboxing. Cela peut être utile parfois, car cela vous permet de sauvegarder n'importe quel type dans une collection (en utilisant object au lieu de T dans une collection générique), mais en général, il est préférable d'éviter cela, car vous perdez la sécurité du type. Le seul cas où la boxe se produit fréquemment, cependant, est lorsque vous utilisez la réflexion - de nombreux appels en réflexion nécessiteront une boxe / unboxing lors de l'utilisation de types de valeur, car le type n'est pas connu à l'avance.

Autres conseils

Il n’existe presque jamais de bonne raison de sceller délibérément un type de valeur. Presque toujours, la raison d'encadrer un type de valeur est de le stocker dans une collection qui n'est pas sensible au type. La vieille ArrayList , par exemple, est une collection. d'objets, qui sont des types de référence. Le seul moyen de collecter, par exemple, des entiers, consiste à les mettre en boîte en tant qu’objets et à les transmettre à ArrayList.

De nos jours, nous avons des collections génériques, ce qui pose moins de problèmes.

La boxe se produit généralement automatiquement dans .NET quand ils le doivent. Souvent, lorsque vous passez un type de valeur à quelque chose qui attend un type de référence. String.Format () est un exemple courant. Lorsque vous transmettez des types de valeur primitifs à cette méthode, ils sont mis en boîte dans le cadre de l'appel. Donc:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

Ceci illustre un scénario simple dans lequel un type de valeur (x) est automatiquement mis en boîte pour être passé à une méthode qui attend un objet. En règle générale, vous voulez éviter les types de valeur de boxe lorsque cela est possible ... mais dans certains cas, cela est très utile.

Fait intéressant, lorsque vous utilisez des génériques dans .NET, les types de valeur ne sont pas encadrés lorsqu'ils sont utilisés en tant que paramètres ou membres du type. Ce qui rend les génériques plus efficaces que les anciens codes C # (tels que ArrayList) qui traitent tout comme {objet} pour qu’il soit indépendant du type. Ceci ajoute une raison supplémentaire d'utiliser des collections génériques, telles que List<T> ou Dictionary<T,K> sur ArrayList ou Hashtable.

Je vous recommanderais 2 beaux articles d'Eric Lippert

http : //blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

Voici la citation avec laquelle je suis d'accord à 100%

  

Utilisation de la pile pour les locales de valeur   le type est juste une optimisation que le   CLR effectue en votre nom.   La caractéristique pertinente des types de valeur est   qu'ils ont la sémantique d'être   copié par valeur, pas que parfois   leur désallocation peut être optimisée par   le runtime.

Dans 99% des applications, les développeurs ne devraient pas se soucier de savoir pourquoi les types Value sont empilés et non dans le tas, et quel gain de performances pourrions-nous avoir ici. Juts a en tête des règles très simples:

  1. Évitez de boxer / déballer sinon nécessaire, utilisez des collections de génériques. La plupart des problèmes ne surviennent pas lorsque vous définir vos propres types, mais quand vous utiliser les types existants de manière inappropriée (défini par Microsoft ou votre collègues)
  2. Faites vos types de valeur simple. Si vous avez besoin d'une structure avec 10-20 champs, je suppose que vous mieux créer une classe. Imagine, tous que les champs seront copiés à chaque fois quand vous passez de temps en temps un fonction par valeur ...
  3. Je ne pense pas qu'il soit très utile d'avoir types de valeur avec type de référence champs à l'intérieur. Comme struct avec Chaîne et champs d'objet.
  4. Définissez le type dont vous avez besoin en fonction de fonctionnalité requise, pas sur il devrait être stocké. Les structures ont fonctionnalité limitée comparant à classes, donc si struct ne peut pas fournir la fonctionnalité requise, comme constructeur par défaut, définir la classe.
  5. Si quelque chose peut en exécuter actions avec les données d'autres types, il est généralement défini comme un classe. Pour les opérations de struct avec différents types doivent être définis que si vous pouvez lancer un type à un autre. Dites que vous pouvez ajouter int à doubler parce que vous pouvez lancer int à double.
  6. Si quelque chose doit être sans état, c'est une classe.
  7. Lorsque vous hésitez, utilisez des types de référence. : -)

Toutes les règles permettent des exclusions dans des cas particuliers, mais n'essayez pas de trop optimiser.

p.s. J'ai rencontré des développeurs ASP.NET avec 2 ou 3 années d'expérience qui ne connaissaient pas la différence entre pile et tas. :-( Je ne ferais pas appel à une telle personne si je suis un intervieweur, mais pas parce que la boxe / le déballage peuvent être un goulot d'étranglement dans l'un des sites ASP.NET que j'ai vus.

Je pense qu'un bon exemple de boxe en c # apparaît dans les collections non génériques telles que ArrayList .

Par exemple, lorsqu'une méthode prend un paramètre d'objet et qu'un type de valeur doit être passé.

Ci-dessous quelques exemples de boxe / déballage

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing

Une des situations dans lesquelles cela se produit est par exemple si vous avez une méthode qui attend un paramètre de type objet et que vous passez dans l’un des types primitifs, int par exemple. Ou si vous définissez le paramètre comme 'ref' de type int.

Le code

int x = 42;
Console.Writeline("The value of x is {0}", x );

en fait, box et unboxes parce que Writeline effectue un int casting à l'intérieur. Pour éviter cela, vous pourriez le faire

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

Méfiez-vous des insectes subtils!

Vous pouvez déclarer vos propres types de valeur en déclarant votre propre type comme struct. Imaginez que vous déclariez un ArrayList avec beaucoup de propriétés, puis que vous placiez des instances dans un []. Cela les encadre bien sûr. Référencez-en un maintenant avec l'opérateur readonly, en le convertissant en type et en définissant une propriété. Vous venez de définir une propriété sur une copie . Celui du <=> n’a toujours pas été modifié.

Pour cette raison, les types de valeur doivent toujours être immuables, c’est-à-dire rendre toutes les variables membres <=> afin qu’elles ne puissent être définies que dans le constructeur et ne possèdent aucun type mutable en tant que membres.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top