12
votes

Pourquoi la méthode générique avec la contrainte de T: classe entraîne-t-elle la boxe?

Pourquoi une méthode générique qui contrainte T à la classe aurait des instructions de boxe dans le code MSIL génère?

J'étais assez surprise par cela depuis que t est certainement contraint à un type de référence, le code généré ne doit pas nécessairement effectuer Toute boxe.

voici le code C #: xxx

voici le IL généré: xxx < P> Notez la case ! T instructions.

Pourquoi cela est généré?

Comment éviter cela?


4 commentaires

Le gist de la réponse que j'ai lié est qu'une instruction de boxe sur un type de référence est efficacement un NOP. Cela permet au compilateur d'émettre librement des instructions de boxe pouvant être supprimées par le JIT pour des types construits fermés créés avec un type de référence en tant qu'argument de type générique. Dans votre cas (puisque t est contraint comme un type de référence) Aucune des deux instructions de boxe émises ne serait jamais exécutée.


Ceux-ci seront de toute façon non ops pour les types de référence, donc ce n'est pas un gros problème, mais j'ai une suspicion. Vous compilez avec / optimiser + ?


Merci Andrew. J'ai effectué des recherches sur les génériques et la boxe, mais je n'ai pas trouvé cette question. Je suppose que, que le compilateur ne se dérange pas de mettre en œuvre une logique spéciale pour cela - car l'opération de la boîte finit par ne rien faire. Pas sûr, si c'est la bonne façon de le faire, mais si vous voulez poster cela comme une réponse, je vais le marquer comme accepté. Acclamations!


En réponse à votre question Pavel - ne le pensez pas, c'est-à-dire d'une version de débogage, et les paramètres du projet ont la case «Optimiser le code» décoché.


4 Réponses :


0
votes

Je crois que cela est destiné à la conception. Vous n'êtes pas contraignant à une classe spécifique, il est donc probablement le casse-couché. Par conséquent, pourquoi vous voyez que l'IL inclut la boxe.

Je voudrais essayer ce code avec où T :Class


4 commentaires

Si vous faites T :Class, pourquoi vous embêter avec les génériques?


Parce que vous pouvez contraindre à des niveaux plus élevés ... comme IsomeInterface ...


Chris, si t était un objet, n'aurait-il pas déjà été encadré avant de pousser sur la pile? Pourquoi une opération de boxe doit-elle être effectuée dessus? Je m'attendrais à ce que l'opérateur == vérifie l'égalité de référence si t était un objet, cela ne nécessiterait donc pas d'opérations d'ONU / boxe.


@RoberTharevey Juste pour poser ce différend âgé de 10 ans au repos et pour confirmer que ce malheureux C # comportement prévaut toujours en 2019, les instructions de boxe injustifiées sont effectivement émises même lorsqu'ils sont contraignants à une classe dérivée où T: Class , par opposition à ce que l'OP spécifié où T: classe , dans laquelle le second implique probablement un "type de référence le moins dérivé" (et note - pas system.Object , à partir duquel system.valuetype dérive théoriquement).



1
votes

Je ne suis pas sûr de savoir pourquoi une boxe est devence. Un moyen possible d'éviter la boxe est de ne pas l'utiliser. Juste recompiler sans la boxe. Ex: xxx

... Si vous économisez sur un fichier recomp_srp.msil, vous pouvez simplement recompiler comme tel:

ildasme / dll recomp_srp.msil < p> Et il fonctionne bien sans la boxe à ma fin: xxx

... Bien sûr, je l'ai changé de protégé au public, vous auriez besoin de faire le changement de retour encore et fournir le reste de votre implémentation.


1 commentaires

MDR. Bien que ce soit en effet une solution appropriée (et, si je me vante, un qui arrive maintenant être de voie trivialement disponible pour moi , grâce aux efforts effrontés d'un voyage pénible et de longue date à l'insuissance et mystique Mixed C # / IL Assemblée), je doute que la plupart des personnes soient prêtes à passer de C # à IL pour faciliter cette solution de bogue.



2
votes

Vous n'avez pas à vous soucier des performances de la performance des instructions BOX car si son argument est un type de référence, l'instruction BOX ne fait rien. Bien qu'il soit toujours étrange que l'instruction ait été créée (peut-être la baisse / la conception plus facile à la génération de code?).


0 commentaires

0
votes

Suivi des points sur quelques points. Tout d'abord, ce bug survient pour les deux méthodes dans une classe générique avec contrainte où T: classe ainsi que méthodes génériques avec cette même contrainte ( dans une classe générique ou non générique). Il ne se produit pas pour une méthode non générique (sinon identique) qui utilise objet au lieu de t : xxx

remarque quelques problèmes supplémentaires avec le premier exemple. Au lieu de simplement ldnull , nous avons un iniobj appellez injustement ciblant inutilement une variable locale en excès TMP .

La bonne nouvelle cependant , allongé-à ici , n'est qu'aucune de ces questions. Malgré les différences de code IL générées pour les deux exemples ci-dessus, la X64 JIT génère du code presque identique pour eux. Le résultat suivant est destiné à .NET Framework 4.7.2 Mode de sortie avec optimisation "non supprimé".

 Entrez la description de l'image ici


0 commentaires