Gibt das Unboxing einfach einen Zeiger auf den Wert innerhalb des Boxed -Objekts auf dem Haufen zurück?

StackOverflow https://stackoverflow.com/questions/2978647

  •  24-10-2019
  •  | 
  •  

Frage

ich Dieser Artikel von MSDN Magazine, der Autor erklärt (Hervorhebung Mine):

Beachten Sie, dass das Boxen immer ein neues Objekt erstellt und die Bits des Unbox -Werts an das Objekt kopiert. Auf der anderen Seite gibt Unboxing einfach einen Zeiger auf die Daten in einem Boxed -Objekt zurück: Es tritt keine Speicherkopie auf. Es ist jedoch üblicherweise der Fall, dass Ihr Code die Daten, auf die der Unbox -Referenz hingewiesen wurde, ohnehin kopiert werden.

Ich bin verwirrt über den Satz, den ich fett gemacht habe, und den Satz, der ihm folgt. Von allem anderen, was ich gelesen habe, einschließlich Diese MSDN -Seite, Ich habe noch nie gehört, dass das Unboxing nur einen Zeiger auf den Wert auf dem Haufen zurückgibt. Ich hatte den Eindruck, dass Unboxing dazu führen würde, dass Sie eine Variable mit einer Kopie des Wertes auf dem Stapel enthalten, so wie Sie begonnen haben. Wenn meine Variable "einen Zeiger auf den Wert auf dem Haufen" enthält, habe ich keinen Werttyp, ich habe einen Zeiger.

Kann jemand erklären, was das bedeutet? War der Autor auf Crack? (Es gibt mindestens einen weiteren eklatanten Fehler im Artikel). Und wenn dies zutrifft, auf welche Fälle, auf die "Ihr Code die Daten durch den Unbox -Referenz sowieso kopiert werden" verursacht?

Mir ist gerade aufgefallen, dass der Artikel fast 10 Jahre alt ist. Vielleicht hat sich dies sehr früh im Leben von .NET geändert.

War es hilfreich?

Lösung

Der Artikel ist korrekt. Es spricht jedoch darüber, was Ja wirklich Gehen weiter, nicht das, was der IL so aussieht, dass der Compiler generiert. Schließlich führt ein .NET -Programm IL nie aus, sondern führt den Maschinencode aus, der vom JIT -Compiler aus dem IL generiert wird.

Und der Unbox -Opcode generiert tatsächlich Code, der einen Zeiger auf die Bits auf dem Heap erzeugt, der den Wert des Werttyps darstellt. Der JIT generiert einen Aufruf einer kleinen Helferfunktion in der CLR mit dem Namen "Jit_unbox". clr src vm jithelpers.cpp Wenn Sie den SSCLI20 -Quellcode erhalten haben. Das Objekt :: getData () -Funktion gibt den Zeiger zurück.

Von dort aus wird der Wert am häufigsten in ein CPU -Register kopiert. Was dann irgendwo aufbewahrt werden kann. Es muss nicht der Stapel sein, es könnte ein Mitglied eines Referenztyp -Objekts (der GC -Haufen) sein. Oder eine statische Variable (der Laderhaufen). Oder es kann auf den Stapel gedrückt werden (Methodenaufruf). Oder das CPU-Register kann als IS verwendet werden, wenn der Wert in einem Ausdruck verwendet wird.

Klicken Sie beim Debuggen mit der rechten Maustaste auf das Editor-Fenster und wählen Sie "Gehen Sie zur Demontage", um den Maschinencode anzuzeigen.

Andere Tipps

Der Autor des ursprünglichen Artikels muss sich auf das beziehen, was auf IL -Ebene passiert. Es gibt zwei Unboxing -Opcodes: unbox und unbox.any.

Laut MSDN, bezüglich unbox.any:

Bei der Anwendung auf die Boxed Form eines Werttyps extrahiert die Unbox.aner Anweisungen den Wert, der in OBJ (vom Typ O) enthalten ist, und entspricht daher dem Unbox, gefolgt von LDOBJ.

und bezüglich unbox:

...] Unbox ist nicht erforderlich, um den Werttyp aus dem Objekt zu kopieren. Normalerweise berechnet es einfach die Adresse des Werttyps, der bereits innerhalb des Boxed -Objekts vorhanden ist.

Also wusste der Autor, wovon er sprach.

Diese kleine Tatsache über unbox Ermöglicht es, bestimmte raffinierte Optimierungen bei direkter Arbeit mit IL durchzuführen. Wenn Sie beispielsweise eine Boxed INT haben, die Sie an eine Funktion übergeben müssen, die einen Ref int akzeptiert, können Sie einfach eine ausgeben unbox Opcode und der Verweis auf das INT ist im Stapel bereit, damit die Funktion operieren kann. In diesem Fall ändert die Funktion den tatsächlichen Inhalt des Boxobjekts, was auf der C# -Ebene unmöglich ist. Es speichert Sie vor der Notwendigkeit, Platz für eine temporäre lokale Variable zuzuweisen, das int dort zu entbinden, einen Ref an die INT an die Funktion zu übergeben und dann ein neues Boxobjekt zu erstellen, um die INT erneut zu beenden und die alte Box zu verwerfen.

Wenn Sie auf der C# -Ebene arbeiten, können Sie natürlich keine solchen Optimierungen durchführen, so davon.

Boxen ist der Akt des Schreibens einer Mehrwert-Instanz auf eine Referenzinstanz (entweder eine object oder eine Schnittstelle) und Referenztypen werden auf dem Haufen zugewiesen.

Nach 'C# 4.0 Kurz gesagt': "... Unboxing Kopien Der Inhalt des Objekts zurück in eine Mehrwert-Instanz "und das impliziert den Stapel.

In dem Artikel, den Sie verweisen, gibt der Autor an:

public static void Main() {

   Int32 v = 5;    // Create an unboxed value type variable
   Object o = v;   // o refers to a boxed version of v
   v = 123;        // Changes the unboxed value to 123

   Console.WriteLine(v + ", " + (Int32) o);    // Displays "123, 5"
}

Können Sie aus diesem Code aus erraten, wie viele Boxvorgänge stattfinden? Sie könnten überrascht sein zu entdecken, dass die Antwort drei ist! Lassen Sie uns den Code sorgfältig analysieren, um wirklich zu verstehen, was los ist. Zunächst wird ein INT32 -Wertentyp (v -Boxed -Wert (v) auf 5 initialisiert. Dann wird ein Objektreferenztyp (O) erstellt, und er möchte auf v. Aber Referenztypen müssen immer auf Objekte im Heap verweisen, sodass C# generiert ist Der richtige IL -Code zu Box V und speicherte die Adresse der Boxed -Version von V in o. Jetzt ist 123 uneingeschränkt und die referenzierten Daten werden in den Wert von Unboxed -Wert V kopiert. Dies hat keinen Einfluss auf die Boxed -Version von V, sodass die Boxed -Version ihren Wert von 5 hält. Beachten Sie, dass dieses Beispiel zeigt, wie O nicht begleitet ist (was einen Zeiger auf die Daten in o zurückgibt). und dann ist die Daten in o Speicher auf den Wert von Unboxed -Wert v.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top