Warum structs werden müssen, boxed?
In C#, beliebige Benutzer-definierte struct
wird automatisch eine Unterklasse von System.Struct System.ValueType
und System.Struct System.ValueType
ist eine Unterklasse von System.Object
.
Aber wenn wir vergeben einige struct Objekt-Typ Referenz-es wird geboxt. Zum Beispiel:
struct A
{
public int i;
}
A a;
object obj = a; //boxing takes place here
Also meine Frage ist: wenn A
ist ein Nachkomme von System.Object
, kann nicht der compiler up-cast es um Objekt-Typ anstelle von Boxen?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Eine Struktur ist ein Werttyp.
System.Object
ist ein Referenz-Typ. Wert-Typen und Referenz-Typen gespeichert werden und anders behandelt von der Laufzeit. Für einen Werttyp behandelt werden als ein Referenz-Typ, es ist erforderlich für Sie geschachtelt werden. Von einem niedrigen Niveau, Perspektive, dazu gehört auch die Vervielfältigung der Wert aus dem stack, wo Sie ursprünglich Leben Sie in den neu zugewiesenen Speicher auf dem heap, was auch ein Objekt enthält header. Die zusätzlichen Header sind notwendig für Referenz-Typen, um zu beheben Ihre vtables zu ermöglichen virtuelle Methode löst und der andere Typ der Referenz bezogene Funktionen (denken Sie daran, dass eine struct auf dem stack ist nur ein Wert und es hat null Informationen geben; es muss nicht alles enthalten, wie vtables und können nicht direkt verwendet, um dynamisch ausgelöst Methoden). Außerdem behandeln etwas wie ein Referenz-Typ, haben Sie eine Referenz (pointer), nicht die raw-Wert.Auf einer niedrigeren Ebene, ein Wert, der nicht erbt nichts. Tatsächlich, wie ich schon sagte, es ist nicht wirklich ein Objekt. Die Tatsache, dass Eine stammt aus
System.ValueType
die wiederum leitet sich vonSystem.Object
ist etwas definiert, in der Abstraktion von der Programmiersprache (C#) und C# ist in der Tat ausblenden der Boxen Betrieb von Ihnen ziemlich gut. Sie nicht erwähnen, was explizit auf der box den Wert, so können Sie einfach denken, dass der compiler hat "upcasted" die Struktur für Sie. Es ist die illusion von Vererbung und Polymorphie für Werte, während keine der notwendigen Werkzeuge für die polymorphe Verhalten ist direkt von Ihnen zur Verfügung.constrained
IL-Anweisung. Was ich meinte ist aber etwas rufen wieToString
auf eine Struktur gegossen, umSystem.Object
oder sagen,IComparable.CompareTo
auf eine Box-integer-statisch typisierte wieIComparable
. Ich denke vtable-lookup erforderlich ist hier, nicht wahr?2.ToString()
wird die box2
. Durch die Art und Weise, ist es möglich zu zeigen, diese Tatsache mit C# - code nur? Ich meine, kurz nach der Demontage, oder Graben durchWinDbg
...System.Object
keine Methode, die mutiert bei einem boxed-Wert und ich weiß nicht, einen Weg, dies zu beweisen.Hier ist, wie ich es vorziehen, daran zu denken. Betrachten Sie die Umsetzung einer variable mit einem 32-bit-integer. Wenn behandelt als einen Wert geben, den gesamten Wert passt in 32-bit-Speicher. Das ist es, was einen Wert geben ist: der Speicher enthält nur die bits, aus denen sich der Wert, nichts mehr, nichts weniger.
Betrachten wir nun die Implementierung eine variable, die eine Referenz auf ein Objekt. Die variable enthält einen "Verweis", das umgesetzt werden könnte in einer beliebigen Anzahl von Möglichkeiten. Es könnte ein Griff in eine garbage-Kollektor-Struktur, oder es könnte eine Adresse sein, die auf dem verwalteten heap, oder was auch immer. Aber es ist etwas, das Ihnen erlaubt um ein Objekt zu finden. Das ist, was ein Referenz-Typ ist: der Speicher für eine variable eines Referenz-Typs enthält einige bits, die es ermöglichen, einen Verweis auf ein Objekt.
Eindeutig diese beiden Dinge sind völlig Verschieden.
Angenommen Sie haben eine variable vom Typ object, und Sie möchten, kopieren Sie den Inhalt einer Variablen vom Typ int in es. Wie machst du es? Die 32 bit einer Ganzzahl nicht einer von diesen "Referenz" Sachen, es ist nur ein Eimer enthält 32 bits. Referenzen könnte 64-bit-Zeiger in den verwalteten heap, oder 32-bit-handles in einem garbage-collector-Daten-Struktur oder jede andere Implementierung, die Sie an denken kann, aber eine 32-bit-integer kann nur ein 32-bit-integer.
Also, was Sie tun in diesem Szenario, Sie die box die ganze Zahl: Sie machen ein neues Objekt, das enthält Speicher für einen integer, und dann speichern Sie eine Referenz auf das neue Objekt.
Boxen ist nur erforderlich, wenn Sie (1) über ein einheitliches system, und (2) sicherzustellen, dass eine 32-bit-integer verbraucht 32-bit Speicher. Wenn Sie bereit sind, ablehnen entweder von denen, dann brauchen Sie nicht Boxen; wir sind nicht bereit, zu verwerfen, und so Boxen ist es, was wir gezwungen sind zu Leben.
Während die Designer von .NETTO sicherlich nicht brauchen, um Boxen in Abschnitt 4.3 der C# - Programmiersprachenspezifikation, erklärt die Absicht dahinter ganz gut, IMO:
Weil Wert-Typen sind nicht-Referenz-Typen (welches System.Objekt letztendlich ist), das Gesetz des Boxens vorhanden ist, um ein unified type system, wo der Wert der alles werden kann als ein Objekt dargestellt.
Dies ist ein Unterschied zu sagen, C++, wo der Typ-system ist nicht einheitlich, es gibt keine gemeinsame Basis-Typ für alle Typen.
System.ValueType
undSystem.Enum
), aber nicht Referenz-Typen. Das ist Unsinn & lässt mich vermuten, dass der C# - Spezifikation ungenau ist. @EricLippert: ich wäre interessiert Ihre Meinung zu meine Antwort.T
wirklich leitet sich vonU
eine Umstellung vonT
zuU
ist Identität-Erhaltung ist keine "irrelevante detail". Der C# - Spezifikation verwenden möglicherweise eine definition von "leitet", die überhaupt umfasst Arten, deren Konvertierungen sind nicht Identität bewahren, aber das bedeutet nicht, dass eine solche definition ist hilfreich.struct
ist ein Wert-Typ design, daher muss es sein, boxed, wenn sich in ein Referenz-Typ.struct
stammt ausSystem.ValueType
, die im Begriff stammt ausSystem.Object
.Die bloße Tatsache, dass struct ist ein Nachkomme des Objekts, bedeutet nicht viel..da die CLR befasst sich mit
structs
anders zur Laufzeit als ein Referenz-Typ.Nachdem die Frage beantwortet wurde Stelle ich eine kleine "trick" in Bezug auf das Thema:
struct
s können Schnittstellen implementieren. Wenn Sie einen Werttyp übergeben an eine Funktion, die erwartet, dass eine Schnittstelle, die diese Wert-Typ implementiert die Wert bekommt normalerweise boxed. Die Verwendung von Generika können Sie vermeiden, die Boxen:Nein, ganz einfach, weil nach der definition der Sprache C#, die "up-casting" in diesem Fall ist Boxen.
Den language-Spezifikation für C# enthält (in Kapitel 13) einen Katalog aller möglichen Konvertierungen. Alle diese Konvertierungen sind kategorisiert in einer bestimmten Weise (z.B. numerische Konvertierungen, Referenz-Konvertierungen, etc.).
Gibt es implizite Konvertierungen von einer Art
S
seiner super-TypT
, aber diese sind nur definiert für das Muster "von einem Klasse TypS
zu einem Referenz-TypT
". Weil Ihrstruct A
ist nicht eine Klasse geben, diese Konvertierungen nicht angewandt werden können, in Ihrem Beispiel.Dass ist die Tatsache, dass
A
ist (indirekt) abgeleitet ausobject
(zwar korrekt) ist einfach irrelevant hier. Was relevant ist, ist, dassA
ist eine Struktur, Wert Typ.Den nur bestehende Umsetzung, die dem Muster entspricht "von einem Werttyp
A
seiner Referenz-super-Typobject
" wird kategorisiert, wie ein boxing-Konvertierung. So hat jeder Konvertierung von einemstruct
zuobject
ist per definition als Boxen.