Frage Ruft das Aufrufen einer Methode für einen Werttyp das Boxen in .NET auf?


Ich habe gerade an der Stack Overflow-Frage teilgenommen Ist alles in .NET ein Objekt?.

Und ein Poster (in Kommentaren der akzeptierten Antwort) schien zu denken, dass das Ausführen eines Methodenaufrufs auf einen Werttyp zum Boxen führte. Er wies mich darauf hin Boxen und Unboxing (C # -Programmierhandbuch) was nicht genau den Anwendungsfall beschreibt, den wir beschreiben.

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

Um weiter zu erarbeiten:

Das Beispiel, das ich verwendet habe, war:

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

Boxen tut nicht auftreten, wenn die betreffende Struktur die vom Objekt geerbte Methode überschreibt, wie die akzeptierte Antwort hier angibt.

Wenn die Struktur die Methode jedoch nicht überschreibt, CIL Befehl wird vor einem Callvirt ausgeführt. Laut der Dokumentation, OpCodes.Constrained Feld, Das führt zum Boxen:

Wenn thisType ein Werttyp ist und   thisType implementiert keine Methode   dann wird ptr dereferenziert, eingerahmt und   übergeben als der 'dieser' Zeiger auf die   Callvirt-Methodenanweisung.


24
2018-01-12 18:04


Ursprung


Antworten:


Hier ist die IL für Ihren 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

Also die Antwort in diesem Fall ist nein.


17
2018-01-12 18:14



In dem Fall, dass Sie die Antwort gegeben haben, ist nein, wie auf den Sockel 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();

Tut 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 

Dies tut jedoch:

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 

11
2018-01-12 18:30



@ggf31316

"Ich glaube, dass ToString aufrufen,   Equals und Gethashcode ergeben   Boxen, wenn die Struktur nicht   überschreiben Sie die Methoden. "

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

Also der Code war so:

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 (über 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

Nun, obwohl kein Box-Call stattfindet, wenn du nachschaust die Dokumentation über eine Constrained + eine Call-VirtSie werden feststellen, dass das Boxen stattfindet. oOo

Zitat:

Wenn thisType ein Werttyp ist und   thisType implementiert keine Methode   dann wird ptr dereferenziert, eingerahmt und   übergeben als der 'dieser' Zeiger auf die   Callvirt-Methodenanweisung.


7
2018-01-13 11:30



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


4
2018-01-13 00:26