L'appel d'une méthode sur un type de valeur entraîne-t-il la boxe dans .NET?
-
22-07-2019 - |
Question
Je ne faisais que participer à la question Stack Overflow Tout est-il en .NET? objet? .
Et une affiche (dans les commentaires de la réponse acceptée) semblait penser que l'exécution d'un appel de méthode sur un type de valeur entraînait la boxe. Il m’a dirigé vers Boxing et Unboxing (programmation en C #) Guide) qui ne spécifie pas exactement le cas d'utilisation que nous décrivons.
Je ne suis pas du genre à faire confiance à une source unique, alors je voulais simplement obtenir de plus amples commentaires sur la question. Mon intuition est qu'il n'y a pas de boxe mais mon intuition est nulle. : D
Pour en savoir plus:
L'exemple que j'ai utilisé était:
int x = 5;
string s = x.ToString(); // Boxing??
La boxe ne se produit pas si la structure en question redéfinit la méthode héritée de l'objet comme l'indique la réponse acceptée ici.
Cependant, si la structure ne remplace pas la méthode, un "contraindre" La commande CIL est exécutée avant un callvirt. Selon la documentation, OpCodes. Champ contraint , cela entraîne la boxe :
Si thisType est un type valeur et thisType n'implémente pas la méthode puis ptr est déréférencé, mis en boîte et passé comme le pointeur 'this' à la instruction de méthode callvirt.
La solution
Voici l'IL pour votre code:
L_0001: ldc.i4.5 // get a 5 on the stack
L_0002: stloc.0 // store into x
L_0003: ldloca.s x // get the address of x on the stack
L_0005: call instance string [mscorlib]System.Int32::ToString() // ToString
L_000a: stloc.1 // store in s
Donc, dans ce cas, la réponse est non.
Autres conseils
Dans le cas où vous avez répondu, non, comme l'a souligné le socle.
Cependant, cela sera le cas si vous appelez une méthode via un pointeur d'interface.
Considérez le code:
interface IZot
{
int F();
}
struct Zot : IZot
{
public int F()
{
return 123;
}
}
Alors
Zot z = new Zot();
z.F();
Ne pas n'entraîne-t-il pas la boxe:
.locals init (
[0] valuetype ConsoleApplication1.Zot z)
L_0000: nop
L_0001: ldloca.s z
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloca.s z
L_000b: call instance int32 ConsoleApplication1.Zot::F()
L_0010: pop
L_0011: ret
Cependant, cela:
IZot z = new Zot();
z.F();
.locals init (
[0] class ConsoleApplication1.IZot z,
[1] valuetype ConsoleApplication1.Zot CS<*><*>)
L_0000: nop
L_0001: ldloca.s CS<*><*>
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloc.1
L_000a: box ConsoleApplication1.Zot
L_000f: stloc.0
L_0010: ldloc.0
L_0011: callvirt instance int32 ConsoleApplication1.IZot::F()
L_0016: pop
@ ggf31316
"Je crois que l'appel de ToString, Equals et Gethashcode résultent en boxe si la structure ne remplacer les méthodes. "
J'ai vérifié ToString pour vous. Int32 remplace ToString, alors j'ai créé une structure qui ne le fait pas. J'ai utilisé .NET Reflector pour m'assurer que la structure ne remplaçait pas magiquement ToString (). et ce ne fut pas le cas.
Le code ressemblait à ceci:
using System;
namespace ConsoleApplication29
{
class Program
{
static void Main(string[] args)
{
MyStruct ms = new MyStruct(5);
string s = ms.ToString();
Console.WriteLine(s);
}
}
struct MyStruct
{
private int m_SomeInt;
public MyStruct(int someInt)
{
m_SomeInt = someInt;
}
public int SomeInt
{
get
{
return m_SomeInt;
}
}
}
}
Et le MSIL (via ILDASM ) pour la méthode Main est la suivante:
IL_0000: ldloca.s ms
IL_0002: ldc.i4.5
IL_0003: call instance void ConsoleApplication29.MyStruct::.ctor(int32)
IL_0008: ldloca.s ms
IL_000a: constrained. ConsoleApplication29.MyStruct
IL_0010: callvirt instance string [mscorlib]System.Object::ToString()
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: ret
Maintenant, malgré l'absence d'appel de boxe, si vous cochez la documentation sur un contraint + un appel virt , vous constaterez qu'il est écrit que la boxe a lieu. oOo
Citation:
Si thisType est un type valeur et thisType n'implémente pas la méthode puis ptr est déréférencé, mis en boîte et passé comme le pointeur 'this' à la instruction de méthode callvirt.
Je crois que l'appel de ToString, Equals et Gethashcode aboutit à une boxe si la structure ne remplace pas les méthodes.