11
votes

Quand une boîte à l'utilisation d'une instruction utilise-t-elle son argument, quand c'est une structure?

J'ai quelques questions sur le code suivant: xxx

Mes questions sont les suivantes:

  • L'Énoncé à l'aide d'utilisations qui fonctionne sur le STRIT STRIT, renvoyée à partir de Test () Boîte de la structure ou non?
  • Comment puis-je trouver la réponse moi-même?

    Pour essayer de trouver moi-même, j'ai inspecté l'IL produite par le code ci-dessus, et voici l'IL pour le principal (...) méthode: < Pré> xxx

    Je soupçonne l'appel à la méthode virtuelle là-bas, sur l_0010 introduira une opération de boxe, mais l'instruction n'est pas ici. .

    La raison pour laquelle je demande, c'est qu'il y a un moment, probablement 1 à 2 ans, j'ai vu en ligne une "optimisation" de l'utilisation de la déclaration utilisée. Le cas était où l'instruction utilisée a été utilisée comme syntaxe pour une serrure de temps courte sur un objet, où la serrure a été acquise dans le procédé et une structure a été renvoyée, qui, lorsqu'elle est éliminée, libérerait la serrure, le code comme celui-ci. : xxx

    et le commentaire était-ce que, en modifiant le type de retour de la méthode LockTheObject de Idisposable à la structure réelle utilisé, la boxe a été évitée.

    Mais je me demande si cela est vrai, sinon vrai.

    Quelqu'un peut-il me dire dans la bonne direction? Si, afin de voir l'opération de la boîte, je devrai inspecter le code d'assemblage d'exécution, montrez-moi s'il vous plaît un exemple de quoi rechercher, je suis bien versé dans le code de l'assemblage afin que ce n'est pas un problème, mais rien n'a sauté chez moi quand j'ai regardé cela non plus.


0 commentaires

3 Réponses :


10
votes

Il apparaît comme si tout type de valeur qui est placé dans un à l'aide de la déclaration ne sera pas en boîte. Cela semble être une optimisation C # car la boxe est uniquement omise lorsqu'un type de valeur implémente Idisposable est dans un à l'aide de la déclaration , non dans aucun autre contexte.

Pour plus d'informations, veuillez vous reporter à Utilisation de la déclaration et de la valeur jetable :

Il y a un moment, Ian Griffiths a écrit à propos de une amélioration de sa classe Timedlock dans lequel il l'a changé d'une classe à une structure. Ce changement a abouti à un Type de valeur qui implémente Idisposable. J'ai eu une question harcelle à l'arrière de mon esprit à l'époque que j'ai vite oublié. Les question est ne serait pas des cas de cette Tapez Get Boxed lorsque vous appelez disposer?

Et aussi oh non! Pas le timedlock à nouveau! :

John Sands souligne une faille dans le code que j'ai montré dans un blog récent pour en utilisant des délits sur les serrures sans abandonner la plus grande partie de la commodité de C # 'S LOCK Mot clé.


1 commentaires

L'interaction entre contrainte et callvirt était ce que je cherchais, merci!



3
votes

Méthodes d'instance sur un type de valeur Prenez un paramètre comme premier argument similaire à la manière dont les méthodes d'instance sur les types de référence font. Cependant, le paramètre dans ce cas est un pointeur géré sur les données de l'objet, pas une référence à un objet en boîte. Vous pourriez le trouver dans la mémoire comme ceci: xxx

données est la même dans ces deux cas¹.

Méthodes d'instance sur un Type de valorisation Attendez-vous au pointeur géré sur les données spécifiquement la boxe des objets n'est pas requise. Comme vous le voyez ci-dessus, l'opcode contraint est utilisé avant l'appel. Il indique à l'exécution que les instructions suivantes CallVirt reçoivent un pointeur géré sur un consoleApplication2.Disposable struct au lieu de la référence d'objet qu'il reçoit normalement. Ce faisant, le JIT peut résoudre la surcharge scellée de Disposer () implémentée par la structure et l'appelez directement sans la boxe de l'objet. Sans le préfixe Contraind , l'objet transmis à l'instruction CallVirt devrait être une référence d'objet, car la procédure de résolution dynamique de l'appel virtuel standard est basée sur le fait que le GC / L'en-tête d'objet est toujours dans l'emplacement prévu - et oui, cela obligerait la boxe pour des types de valeur.

¹ Nous allons aller de l'avant et ignorer nullable pour l'instant.


0 commentaires

6
votes

Ceci est un duplicata de Si ma structure implémente Idisposable, elle sera encadrée lorsqu'elle est utilisée dans une déclaration utilisée?

Mise à jour: Cette question était Le sujet de mon blog en mars 2011 . Merci pour la grande question! P>

La réponse d'Andrew Hare est correcte; Je voulais juste ajouter une note supplémentaire intéressante. L'optimisation que nous émettons - de l'utilisation de Callvirt contraint pour sauter la boxe lorsque cela est possible - est en fait strictement parlant une violation de la spécification C #. La spécification indique que le choix enfin que nous générons pour une ressource de type de valeur est la suivante: P>

     finally 
     {
         ((IDisposable)resource).Dispose();
     }


2 commentaires

J'ai parfois bouleversé le manque de syntaxe de spécifier un "réinterpret sans boxe". Étant donné que ressource doit être d'un type qui satisferait une contrainte indisposable , je me demande si la spécification pourrait dire que le comportement serait équivalent à appeler statique annulation statique < T> (Ref t it) où il: Idisposable {IT.Dispose ();} , sauf que le compilateur C # générerait probablement le code en ligne [même si le compilateur C # ne l'est pas en ligne , il semblerait que la gigue pourrait].


Bonjour Eric, je me demande si le Callvirt contraint est, à ce jour, toujours une violation de la spécification C #.