2009-01-12 6 views
24

Ich war gerade an Stack Overflow beteiligt Frage Is everything in .NET an object?.Ruft das Aufrufen einer Methode für einen Werttyp das Boxen in .NET auf?

Und ein Poster (in Kommentaren der akzeptierten Antwort) schien zu denken, dass das Ausführen eines Methodenaufrufs auf einem Werttyp zu Boxen führte. Er wies mich auf Boxing and Unboxing (C# Programming Guide), die nicht genau spezifiziert den Anwendungsfall, den wir beschreiben.

Ich bin nicht einer einzigen Quelle zu vertrauen, also wollte ich nur weiteres Feedback zu der Frage bekommen. Meine Intuition ist, dass es kein Boxen gibt, aber meine Intuition ist scheiße. : D

Zur weiteren erarbeiten:

Das Beispiel I verwendet wurde:

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

Boxen tut nicht, wenn die Struktur in Frage kommen die Methode aus dem Objekt als akzeptierte Antwort geerbt hat Vorrang vor hier Zustände.

Wenn jedoch die Struktur die Methode nicht überschreibt, wird vor einer Callvirt ein "constrain" CIL Befehl ausgeführt. Gemäß der Dokumentation, OpCodes.Constrained Field führt dies im Boxen:

Wenn thisType ein Werttyp ist und thisType nicht implementiert Methode dann ptr dereferenziert, geboxt, und als ‚diese weitergegeben 'Zeiger auf die callvirt-Methodenanweisung .

+0

Und der Grund hier: http://stackoverflow.com/questions/1359856/why-does-implicitly-calling-tostring-on-a-value-type-cause-a-box-instruction – nawfal

Antwort

17

Hier ist die IL-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 

Die Antwort ist in diesem Fall nicht.

+1

Ein wichtiger Beachten Sie, dass die ToString-Methode nicht für den Wert von x, sondern für die Adresse von x aufgerufen wird. Beachten Sie die Anweisung ldloc ** a **. – swax

11

In dem Fall, dass Sie die Antwort gegeben haben ist nein, wie der Sockel darauf hingewiesen.

Es wird jedoch, wenn Sie eine Methode über einen Schnittstellenzeiger aufrufen.

Betrachten Sie den Code:

interface IZot 
{ 
    int F(); 
} 

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

Dann

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

Does nicht Ergebnis im Boxen:

.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 

Doch dies tut:

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

Ich glaube, dass das Aufrufen von ToString, Equals und Gethashcode zum Boxen führt, wenn die Struktur die Methoden nicht überschreibt.

+0

einfach, direkt auf den Punkt. sollte die richtige Antwort sein – nawfal

7

@ggf31316

"Ich glaube, dass ToString Aufruf Equals und GetHashCode Ergebnis in Boxen, wenn die Struktur nicht überschreibt die Methoden."

Ich habe ToString für Sie überprüft. Int32 überschreibt ToString, also habe ich eine Struktur erstellt, die das nicht tut. Ich habe .NET Reflector verwendet, um sicherzustellen, dass die Struktur ToString() nicht irgendwie magisch überschreibt, und das war es auch nicht.

So ist der Code wie folgt war:

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; 
      } 
     } 
    } 
} 

Und die MSIL (via ILDASM) für die Main-Methode, ist dies:

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 

Jetzt, obwohl es keinen Anruf Boxen statt, wenn Sie Überprüfen Sie the documentation about a constrained + a call virt, finden Sie es besagt, dass Boxen stattfindet. oOo

Zitat:

Wenn thisType ein Typ Wert ist und thisType nicht implementiert Methode dann ptr dereferenziert, geboxt, und als ‚dieser‘ Zeiger auf die callvirt Methode Anweisung übergeben.

Verwandte Themen