2009-01-12 4 views
24

Je participais juste à la question Stack Overflow Is everything in .NET an object?.L'appel d'une méthode sur un type de valeur entraîne-t-il une boxe dans .NET?

Et une affiche (dans les commentaires de la réponse acceptée) a semblé penser que l'exécution d'un appel de méthode sur un type de valeur entraînait la boxe. Il m'a indiqué Boxing and Unboxing (C# Programming Guide) qui ne spécifie pas exactement le cas d'utilisation que nous décrivons. Je ne suis pas du genre à faire confiance à une seule source, alors je voulais juste obtenir plus de commentaires sur la question. Mon intuition est qu'il n'y a pas de boxe mais mon intuition est nulle. : D

Pour élaborer davantage:

L'exemple que j'utilisé était:

int x = 5; 
string s = x.ToString(); // Boxing?? 

boxe ne pas se produire si le struct en question remplace la méthode héritée de l'objet comme la réponse acceptée ici États.

Toutefois, si la structure ne remplace pas la méthode, une commande "contrain" CIL est exécutée avant un callvirt. Selon la documentation, OpCodes.Constrained Field, cela se traduit dans la boxe:

Si thisType est un type de valeur et thisType ne met pas en œuvre la méthode alors ptr est déréférencé, emballé et passé comme « cette 'pointeur vers l'instruction de méthode callvirt .

+0

Et voici la raison: http://stackoverflow.com/questions/1359856/why-does-implicitly-calling-tostring-on-a-value-type-cause-a-box-instruction – nawfal

Répondre

17

est ici 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 

La réponse dans ce cas est non.

+1

Un important notez ici que la méthode ToString n'est pas appelée par rapport à la valeur de x, mais à l'adresse de x. Notez l'instruction ldloc ** a **. – swax

11

Dans le cas où vous avez donné la réponse est non, comme indiqué plinthe. Cependant, cela sera le cas si vous appelez une méthode via un pointeur d'interface.

Tenir compte du code:

interface IZot 
{ 
    int F(); 
} 

struct Zot : IZot 
{ 
    public int F() 
    { 
     return 123; 
    } 
} 

Puis

Zot z = new Zot(); 
z.F(); 

Est-ce pas résultat dans 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 ne:

IZot z = new Zot(); 
z.F(); 

    .locals init (
     [0] class ConsoleApplication1.IZot z, 
     [1] valuetype ConsoleApplication1.Zot CS$0$0000) 
    L_0000: nop 
    L_0001: ldloca.s CS$0$0000 
    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 
4

Je crois qu'appeler ToString, Equals et Gethashcode aboutir à la boxe si la structure ne remplace pas les méthodes.

+0

simple, droit au but. devrait être la bonne réponse – nawfal

7

@ggf31316

"Je crois que l'appel ToString, Equals et le résultat GetHashCode dans boxe si la structure ne substituer les méthodes."

J'ai vérifié ToString pour vous. Int32 remplace ToString, donc j'ai fait une structure qui ne le fait pas. J'ai utilisé .NET Reflector pour m'assurer que la structure n'était pas en quelque sorte magique ToString(), et ce n'était pas le cas.

Ainsi, le code est comme 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 principale 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é aucun appel de boxe qui aura lieu, si vous vérifiez the documentation about a constrained + a call virt, vous trouverez qu'il indique que la boxe a lieu. oOo

Quote:

Si thisType est un type de valeur et thisType ne met pas en œuvre la méthode alors ptr est déréférencé, en boîte, et passé comme 'ce' pointeur vers l'instruction de la méthode de callvirt.

Questions connexes