In C # können Strukturen nicht von Klassen abgeleitet werden, aber alle ValueTypes werden von Object abgeleitet. Wo wird diese Unterscheidung getroffen?
Wie geht die CLR damit um?
In C # können Strukturen nicht von Klassen abgeleitet werden, aber alle ValueTypes werden von Object abgeleitet. Wo wird diese Unterscheidung getroffen?
Wie geht die CLR damit um?
Antworten:
Mit C # können Strukturen nicht von Klassen abgeleitet werden
Ihre Aussage ist falsch, daher Ihre Verwirrung. C # tut erlauben structs von Klassen abzuleiten. Alle Strukturen stammen von derselben Klasse, System.ValueType, die von System.Object abgeleitet ist. Und alle Aufzählungen stammen von System.Enum.
UPDATE: In einigen (jetzt gelöschten) Kommentaren gab es einige Verwirrung, die einer Klärung bedarf. Ich werde einige zusätzliche Fragen stellen:
Leiten sich Strukturen von einem Basistyp ab?
Einfach ja. Wir können dies sehen, indem wir die erste Seite der Spezifikation lesen:
Alle C # -Typen, einschließlich primitiver Typen wie int und double, erben von einem einzelnen Stammobjekttyp.
Nun stelle ich fest, dass die Spezifikation den Fall hier überbewertet. Zeigertypen werden nicht vom Objekt abgeleitet, und die Ableitungsbeziehung für Schnittstellentypen und Typparametertypen ist komplexer als in dieser Skizze angegeben. Es ist jedoch klar, dass alle Strukturtypen von einem Basistyp abgeleitet sind.
Gibt es andere Möglichkeiten, wie wir wissen, dass Strukturtypen von einem Basistyp abgeleitet sind?
Sicher. Ein Strukturtyp kann überschreiben ToString
. Was überschreibt es, wenn nicht eine virtuelle Methode ihres Basistyps? Daher muss es einen Basistyp haben. Dieser Basistyp ist eine Klasse.
Darf ich eine benutzerdefinierte Struktur aus einer Klasse meiner Wahl ableiten?
Einfach nein. Dies bedeutet nicht, dass Strukturen nicht von einer Klasse abgeleitet sind . Strukturen leiten sich von einer Klasse ab und erben dadurch die vererbbaren Mitglieder dieser Klasse. In der Tat ist structs erforderlich herzuleiten aus einer bestimmten Klasse: Aufzählungen von abzuleiten sind erforderlich Enum
, Strukturen zu von derive erforderlich sind ValueType
. Da diese erforderlich sind , verbietet Ihnen die C # -Sprache die Angabe der Ableitungsbeziehung im Code.
Warum es verbieten?
Wenn eine Beziehung erforderlich ist , hat der Sprachdesigner folgende Optionen: (1) Der Benutzer muss die erforderliche Beschwörung eingeben, (2) sie optional machen oder (3) sie verbieten. Jedes hat Vor- und Nachteile, und die C # -Sprachendesigner haben je nach den jeweiligen Details unterschiedliche Entscheidungen getroffen.
Zum Beispiel müssen const-Felder statisch sein, aber es ist verboten zu sagen, dass dies der Fall ist, da dies erstens eine sinnlose Aussprache ist und zweitens impliziert, dass es nicht statische const-Felder gibt. Überladene Operatoren müssen jedoch als statisch markiert werden, obwohl der Entwickler keine andere Wahl hat. Für Entwickler ist es zu einfach zu glauben, dass eine Operatorüberladung ansonsten eine Instanzmethode ist. Dies überschreibt die Sorge, dass ein Benutzer glauben könnte, dass "statisch" impliziert, dass beispielsweise "virtuell" auch eine Möglichkeit ist.
In diesem Fall dass ein Benutzer sagen , dass ihre Struktur ergibt sich aus Valuetype scheint wie nur überschüssige Wortschwall, und es bedeutet , dass die Struktur könnte von einem anderen Typ abzuleiten. Um diese beiden Probleme zu beseitigen, macht es C # illegal , im Code anzugeben, dass eine Struktur von einem Basistyp abgeleitet ist, obwohl dies eindeutig der Fall ist.
Ebenso leiten sich alle Delegatentypen ab MulticastDelegate
, aber C # erfordert, dass Sie das nicht sagen.
Nun haben wir festgestellt, dass alle Strukturen in C # von einer Klasse abgeleitet sind .
Welche Beziehung besteht zwischen Vererbung und Ableitung von einer Klasse ?
Viele Menschen sind durch die Vererbungsbeziehung in C # verwirrt. Die Vererbungsbeziehung ist recht einfach: Wenn eine Struktur, eine Klasse oder ein Delegat vom Typ D von einem Klassentyp B abgeleitet ist, sind die vererbbaren Mitglieder von B auch Mitglieder von D. So einfach ist das.
Was bedeutet es in Bezug auf die Vererbung, wenn wir sagen, dass eine Struktur von ValueType abgeleitet ist? Einfach, dass alle vererbbaren Mitglieder von ValueType auch Mitglieder der Struktur sind. Auf diese Weise erhalten Strukturen beispielsweise ihre Implementierung von ToString
; Es wird von der Basisklasse der Struktur geerbt.
Alle vererbbaren Mitglieder? Sicher nicht. Sind private Mitglieder vererbbar?
Ja. Alle privaten Mitglieder einer Basisklasse sind auch Mitglieder des abgeleiteten Typs. Es ist natürlich illegal, diese Mitglieder beim Namen anzurufen, wenn sich die Anrufstelle nicht in der Eingabehilfen-Domäne des Mitglieds befindet. Nur weil Sie ein Mitglied haben, heißt das nicht, dass Sie es verwenden können!
Wir fahren nun mit der ursprünglichen Antwort fort:
Wie geht die CLR damit um?
Sehr gut. :-)
Was einen Werttyp zu einem Werttyp macht, ist, dass seine Instanzen nach Wert kopiert werden . Was einen Referenztyp zu einem Referenztyp macht, ist, dass seine Instanzen durch Referenz kopiert werden . Sie scheinen der Ansicht zu sein, dass die Vererbungsbeziehung zwischen Werttypen und Referenztypen irgendwie besonders und ungewöhnlich ist, aber ich verstehe nicht, was dieser Glaube ist. Vererbung hat nichts damit zu tun, wie Dinge kopiert werden.
Schau es dir so an. Angenommen, ich habe Ihnen die folgenden Fakten mitgeteilt:
Es gibt zwei Arten von Boxen, rote Boxen und blaue Boxen.
Jedes rote Kästchen ist leer.
Es gibt drei spezielle blaue Kästchen mit den Namen O, V und E.
O ist in keiner Box.
V ist in O.
E ist in V.
Keine andere blaue Box befindet sich in V.
In E. befindet sich keine blaue Box.
Jedes rote Kästchen ist entweder in V oder E.
Jede andere blaue Box als O befindet sich in einer blauen Box.
Die blauen Kästchen sind Referenztypen, die roten Kästchen sind Werttypen, O ist System.Object, V ist System.ValueType, E ist System.Enum und die "innere" Beziehung ist "abgeleitet von".
Das ist ein perfekt konsistentes und unkompliziertes Regelwerk, das Sie leicht selbst umsetzen können, wenn Sie viel Pappe und viel Geduld haben. Ob eine Box rot oder blau ist, hat nichts mit dem zu tun, was sich darin befindet. In der realen Welt ist es durchaus möglich, eine rote Box in eine blaue Box zu stecken. In der CLR ist es völlig legal, einen Werttyp zu erstellen, der von einem Referenztyp erbt, sofern es sich entweder um System.ValueType oder System.Enum handelt.
Lassen Sie uns also Ihre Frage umformulieren:
Wie leiten sich ValueTypes von Object (ReferenceType) ab und sind dennoch ValueTypes?
wie
Wie ist es möglich, dass sich jede rote Box (Werttypen) in der Box O (System.Object) befindet (von dieser abgeleitet ist), die eine blaue Box (ein Referenztyp) ist und dennoch eine rote Box (ein Werttyp) ist?
Wenn Sie es so formulieren, hoffe ich, dass es offensichtlich ist. Nichts hindert Sie daran, eine rote Box in Box V zu stecken, die sich in Box O befindet, die blau ist. Warum sollte es das geben?
EIN ZUSÄTZLICHES UPDATE:
Joans ursprüngliche Frage war, wie es möglich istdass ein Werttyp von einem Referenztyp abgeleitet ist. Meine ursprüngliche Antwort erklärte keinen der Mechanismen, die die CLR verwendet, um die Tatsache zu erklären, dass wir eine Ableitungsbeziehung zwischen zwei Dingen haben, die völlig unterschiedliche Darstellungen haben - nämlich ob die referenzierten Daten einen Objektheader haben, a Synchronisierungsblock, ob er einen eigenen Speicher zum Zwecke der Speicherbereinigung besitzt, und so weiter. Diese Mechanismen sind kompliziert, zu kompliziert, um sie in einer Antwort zu erklären. Die Regeln des CLR-Typsystems sind etwas komplexer als die etwas vereinfachte Variante, die wir in C # sehen, wo beispielsweise nicht stark zwischen der Box- und der Unbox-Version eines Typs unterschieden wird. Die Einführung von Generika führte auch dazu, dass der CLR eine zusätzliche Komplexität hinzugefügt wurde.
Kleine Korrektur, C # erlaubt nicht, dass Strukturen benutzerdefiniert von irgendetwas abgeleitet werden, nicht nur von Klassen. Eine Struktur kann lediglich eine Schnittstelle implementieren, die sich stark von der Ableitung unterscheidet.
Ich denke, der beste Weg, dies zu beantworten, ValueType
ist etwas Besonderes. Es ist im Wesentlichen die Basisklasse für alle Werttypen im CLR-Typsystem. Es ist schwer zu beantworten, wie "die CLR damit umgeht", da dies einfach eine Regel der CLR ist.
ValueType
ist etwas Besonderes, aber es ist erwähnenswert, dass es ValueType
sich tatsächlich um einen Referenztyp handelt.
Dies ist ein etwas künstliches Konstrukt, das von der CLR verwaltet wird, damit alle Typen als System.Object behandelt werden können.
Werttypen werden von System.Object über System.ValueType abgeleitet . Hier erfolgt die spezielle Behandlung (dh die CLR behandelt das Boxen / Entpacken usw. für alle von ValueType abgeleiteten Typen).
Ihre Aussage ist falsch, daher Ihre Verwirrung. Mit C # können Strukturen von Klassen abgeleitet werden. Alle Strukturen stammen von derselben Klasse, System.ValueType
Versuchen wir also Folgendes:
struct MyStruct : System.ValueType
{
}
Dies wird nicht einmal kompiliert. Der Compiler erinnert Sie daran, dass "Geben Sie 'System.ValueType' in die Schnittstellenliste keine Schnittstelle ein".
Wenn Sie Int32 dekompilieren, das eine Struktur ist, finden Sie:
public struct Int32: IComparable, IFormattable, IConvertible {}, ohne zu erwähnen, dass es von System.ValueType abgeleitet ist. Im Objektbrowser erbt Int32 jedoch von System.ValueType.
All dies lässt mich glauben:
Ich denke, der beste Weg, dies zu beantworten, ist, dass ValueType etwas Besonderes ist. Es ist im Wesentlichen die Basisklasse für alle Werttypen im CLR-Typsystem. Es ist schwer zu beantworten, wie "die CLR damit umgeht", da dies einfach eine Regel der CLR ist.
ValueType
, verwendet sie diese, um zwei Arten von Objekten zu definieren: einen Heap-Objekttyp, der verhält sich wie ein Referenztyp und ein Speicherorttyp, der sich effektiv außerhalb des Typvererbungssystems befindet. Da diese beiden Arten von Dingen in sich gegenseitig ausschließenden Kontexten verwendet werden, können für beide dieselben Typdeskriptoren verwendet werden. Auf der CLR-Ebene wird eine Struktur als Klasse definiert, deren Eltern übergeordnet sind System.ValueType
, aber C # ...
System.ValueType
), und verbietet Klassen die Angabe, von der sie erben, System.ValueType
weil sich jede Klasse, die auf diese Weise deklariert wurde, wie ein Werttyp verhält.
Ein Boxed-Value-Typ ist effektiv ein Referenztyp (er läuft wie einer und quakt wie einer, also ist er effektiv einer). Ich würde vorschlagen, dass ValueType nicht wirklich der Basistyp von Werttypen ist, sondern vielmehr der Basisreferenztyp, in den Werttypen konvertiert werden können, wenn sie in den Typ Object umgewandelt werden. Werttypen ohne Box selbst befinden sich außerhalb der Objekthierarchie.
Von allen Antworten kommt die Antwort von @ supercat der tatsächlichen Antwort am nächsten. Da die anderen Antworten die Frage nicht wirklich beantworten und geradezu falsche Behauptungen aufstellen (zum Beispiel, dass Werttypen von irgendetwas erben), habe ich beschlossen, die Frage zu beantworten.
Diese Antwort basiert auf meinem eigenen Reverse Engineering und der CLI-Spezifikation.
struct
und class
sind C # -Schlüsselwörter. In Bezug auf die CLI werden alle Typen (Klassen, Schnittstellen, Strukturen usw.) durch Klassendefinitionen definiert.
Beispielsweise ist ein Objekttyp (in C # als bekannt class
) wie folgt definiert:
.class MyClass
{
}
Eine Schnittstelle wird durch eine Klassendefinition mit dem interface
semantischen Attribut definiert:
.class interface MyInterface
{
}
Der Grund, warum Strukturen von Werttypen erben können System.ValueType
und immer noch sind, liegt darin, dass sie dies nicht tun.
Werttypen sind einfache Datenstrukturen. Werttypen haben nicht erben nichts und sie können nicht Schnittstellen implementieren. Werttypen sind keine Untertypen und haben keine Typinformationen. Bei einer Speicheradresse eines Werttyps ist es nicht möglich zu identifizieren, was der Werttyp darstellt, im Gegensatz zu einem Referenztyp, der Typinformationen in einem ausgeblendeten Feld enthält.
Wenn wir uns folgende C # -Struktur vorstellen:
namespace MyNamespace
{
struct MyValueType : ICloneable
{
public int A;
public int B;
public int C;
public object Clone()
{
// body omitted
}
}
}
Das Folgende ist die IL-Klassendefinition dieser Struktur:
.class MyNamespace.MyValueType extends [mscorlib]System.ValueType implements [mscorlib]System.ICloneable
{
.field public int32 A;
.field public int32 B;
.field public int32 C;
.method public final hidebysig newslot virtual instance object Clone() cil managed
{
// body omitted
}
}
Also, was ist hier los? Es erweitert sich deutlich System.ValueType
, was ein Objekt- / Referenztyp ist, und implementiert System.ICloneable
.
Die Erklärung ist, dass, wenn eine Klassendefinition erweitert wird System.ValueType
tatsächlich zwei Dinge definiert: einen Werttyp und den entsprechenden Box-Typ des Werttyps. Die Mitglieder der Klassendefinition definieren die Darstellung sowohl für den Werttyp als auch für den entsprechenden Box-Typ. Es ist nicht der Werttyp, der erweitert und implementiert wird, sondern der entsprechende Box-Typ, der dies tut. Die Schlüsselwörter extends
und implements
gelten nur für den Box-Typ.
Zur Verdeutlichung führt die obige Klassendefinition zwei Dinge aus:
System.ValueType
der System.ICloneable
Schnittstelle erbt und diese implementiert .Beachten Sie auch, dass jede erweiterte Klassendefinition System.ValueType
auch intrinsisch versiegelt ist, unabhängig davon, ob diesealed
Schlüsselwort angegeben ist oder nicht.
Da Werttypen nur einfache Strukturen sind, nicht erben, nicht implementieren und keinen Polymorphismus unterstützen, können sie nicht mit dem Rest des Typsystems verwendet werden. Um dies zu umgehen, definiert die CLR zusätzlich zum Werttyp einen entsprechenden Referenztyp mit denselben Feldern, den so genannten Box-Typ. Während ein Werttyp nicht an Methoden weitergegeben werden kann, die ein nehmen object
, kann der entsprechende Box-Typ dies .
Nun, wenn Sie eine Methode in C # wie definieren würden
public static void BlaBla(MyNamespace.MyValueType x)
,
Sie wissen, dass die Methode den Werttyp annimmt MyNamespace.MyValueType
.
Oben haben wir erfahren, dass die Klassendefinition, die sich aus dem struct
Schlüsselwort in C # ergibt, tatsächlich sowohl einen Werttyp als auch einen Objekttyp definiert. Wir können uns jedoch nur auf den definierten Wertetyp beziehen. Obwohl in der CLI-Spezifikation angegeben ist, dass das Constraint-Schlüsselwortboxed
verwendet werden kann, um auf eine Box-Version eines Typs zu verweisen, ist dieses Schlüsselwort nicht vorhanden (siehe ECMA-335, II.13.1 Referenzieren von Werttypen). Aber stellen wir uns vor, dass es für einen Moment so ist.
Wenn auf Typen in IL verwiesen wird, werden einige Einschränkungen unterstützt, darunter class
und valuetype
. Wenn wir verwenden, geben valuetype MyNamespace.MyType
wir die Wertetypklassendefinition mit dem Namen MyNamespace.MyType an. Ebenso können wir class MyNamespace.MyType
die Objekttypklassendefinition mit dem Namen MyNamespace.MyType angeben. Dies bedeutet, dass Sie in IL einen Werttyp (Struktur) und einen Objekttyp (Klasse) mit demselben Namen haben und diese dennoch unterscheiden können. Wenn das in boxed
der CLI-Spezifikation angegebene Schlüsselwort tatsächlich implementiert wäre, könnten wir boxed MyNamespace.MyType
den Box-Typ der Werttyp-Klassendefinition mit dem Namen MyNamespace.MyType angeben.
Nimmt also .method static void Print(valuetype MyNamespace.MyType test) cil managed
den Werttyp, der durch eine Werttypklassendefinition mit dem Namen definiert ist MyNamespace.MyType
,
while .method static void Print(class MyNamespace.MyType test) cil managed
nimmt den Objekttyp, der durch die benannte Objekttypklassendefinition definiert ist MyNamespace.MyType
.
Wenn boxed
es sich um ein Schlüsselwort handelt, wird ebenfalls .method static void Print(boxed MyNamespace.MyType test) cil managed
der Box-Typ des Wertetyps verwendet, der durch eine Klassendefinition mit dem Namen definiert ist MyNamespace.MyType
.
Sie würden dann in der Lage sein , die Box - Typ wie jeder andere Objekttyp instanziiert und es um auf jede Methode übergeben , die eine nimmt System.ValueType
, object
oder boxed MyNamespace.MyValueType
als Argument, und es wäre für alle Absichten und Zwecke, Arbeit wie jede andere Referenztyp. Es ist KEIN Werttyp, sondern der entsprechende Box-Typ eines Werttyps.
Also, zusammenfassend und um die Frage zu beantworten:
Werttypen sind keine Referenztypen und erben nicht von System.ValueType
oder einem anderen Typ und können keine Schnittstellen implementieren. Die entsprechenden Box- Typen, die ebenfalls definiert sind, erben von Schnittstellen System.ValueType
und können diese implementieren.
Eine .class
Definition definiert je nach Umstand unterschiedliche Dinge.
interface
semantische Attribut angegeben ist, definiert die Klassendefinition eine Schnittstelle.interface
semantische Attribut nicht angegeben ist und die Definition nicht erweitert wird System.ValueType
, definiert die Klassendefinition einen Objekttyp (Klasse).interface
semantische Attribut nicht spezifiziert ist, und die Definition nicht erstrecken System.ValueType
, definiert die Klassendefinition einen Werttyp und seinen entsprechenden geschachtelte Typen (struct).In diesem Abschnitt wird ein 32-Bit-Prozess angenommen
Wie bereits erwähnt, haben Werttypen keine Typinformationen, und daher ist es nicht möglich, anhand seines Speicherorts zu identifizieren, was ein Werttyp darstellt. Eine Struktur beschreibt einen einfachen Datentyp und enthält nur die Felder, die sie definiert:
public struct MyStruct
{
public int A;
public short B;
public int C;
}
Wenn wir uns vorstellen, dass eine Instanz von MyStruct unter der Adresse 0x1000 zugewiesen wurde, ist dies das Speicherlayout:
0x1000: int A;
0x1004: short B;
0x1006: 2 byte padding
0x1008: int C;
Strukturen verwenden standardmäßig ein sequentielles Layout. Felder werden an Grenzen ihrer eigenen Größe ausgerichtet. Um dies zu befriedigen, wird eine Polsterung hinzugefügt.
Wenn wir eine Klasse genauso definieren wie:
public class MyClass
{
public int A;
public short B;
public int C;
}
Wenn Sie sich dieselbe Adresse vorstellen, lautet das Speicherlayout wie folgt:
0x1000: Pointer to object header
0x1004: int A;
0x1008: int C;
0x100C: short B;
0x100E: 2 byte padding
0x1010: 4 bytes extra
Klassen verwenden standardmäßig das automatische Layout, und der JIT-Compiler ordnet sie in der optimalen Reihenfolge an. Felder werden an Grenzen ihrer eigenen Größe ausgerichtet. Um dies zu befriedigen, wird eine Polsterung hinzugefügt. Ich bin mir nicht sicher warum, aber jede Klasse hat am Ende immer zusätzliche 4 Bytes.
Offset 0 enthält die Adresse des Objektheaders, der Typinformationen, die virtuelle Methodentabelle usw. enthält. Dadurch kann die Laufzeit im Gegensatz zu Werttypen identifizieren, was die Daten an einer Adresse darstellen.
Werttypen unterstützen daher weder Vererbung, Schnittstellen noch Polymorphismus.
Werttypen haben keine virtuellen Methodentabellen und unterstützen daher keinen Polymorphismus. Der entsprechende Box-Typ tut dies jedoch .
Wenn Sie eine Instanz einer Struktur haben und versuchen, eine virtuelle Methode wie in ToString()
definiert aufzurufen System.Object
, muss die Laufzeit die Struktur boxen.
MyStruct myStruct = new MyStruct();
Console.WriteLine(myStruct.ToString()); // ToString() call causes boxing of MyStruct.
Wenn die Struktur jedoch überschrieben wird, ToString()
wird der Aufruf statisch gebunden und die Laufzeit wird MyStruct.ToString()
ohne Boxen und ohne Suche in virtuellen Methodentabellen aufgerufen (Strukturen haben keine). Aus diesem Grund kann der ToString()
Anruf auch inline geschaltet werden.
Wenn die Struktur überschrieben ToString()
und eingerahmt ist, wird der Aufruf mithilfe der virtuellen Methodentabelle aufgelöst.
System.ValueType myStruct = new MyStruct(); // Creates a new instance of the boxed type of MyStruct.
Console.WriteLine(myStruct.ToString()); // ToString() is now called through the virtual method table.
ToString()
Denken Sie jedoch daran, dass dies in der Struktur definiert ist und daher mit dem Strukturwert arbeitet, sodass ein Werttyp erwartet wird. Der Box-Typ hat wie jede andere Klasse einen Objektheader. Wenn die ToString()
in der Struktur definierte Methode direkt mit dem Box-Typ im this
Zeiger aufgerufen würde, würde beim Versuch, auf das Feld A
in MyStruct
zuzugreifen, auf den Offset 0 zugegriffen, der im Box-Typ der Objekt-Header-Zeiger wäre. Der Boxed-Typ verfügt also über eine versteckte Methode, die das eigentliche Überschreiben ausführt ToString()
. Diese versteckte Methode entpackt (nur Adressberechnung, wie die unbox
IL-Anweisung) den Box-Typ und ruft dann statisch die ToString()
in der Struktur definierten auf.
Ebenso verfügt der Boxed-Typ über eine versteckte Methode für jede implementierte Schnittstellenmethode, die dasselbe Unboxing ausführt und dann die in der Struktur definierte Methode statisch aufruft.
I.8.2.4 Für jeden Werttyp definiert das CTS einen entsprechenden Referenztyp, der als Box-Typ bezeichnet wird. Das Gegenteil ist nicht der Fall: Im Allgemeinen haben Referenztypen keinen entsprechenden Werttyp. Die Darstellung eines Werts eines Box-Typs (eines Box-Werts) ist ein Ort, an dem ein Wert des Werttyps gespeichert werden kann. Ein Box-Typ ist ein Objekttyp und ein Box-Wert ist ein Objekt.
I.8.9.7 Nicht alle durch eine Klassendefinition definierten Typen sind Objekttypen (siehe §I.8.2.3); Insbesondere sind Werttypen keine Objekttypen, sondern werden mithilfe einer Klassendefinition definiert. Eine Klassendefinition für einen Werttyp definiert sowohl den Wertetyp (ohne Box) als auch den zugehörigen Typ mit Box (siehe §I.8.2.4). Die Mitglieder der Klassendefinition definieren die Darstellung von beiden.
II.10.1.3 Die semantischen Attribute des Typs geben an, ob eine Schnittstelle, eine Klasse oder ein Wertetyp definiert werden soll. Das Schnittstellenattribut gibt eine Schnittstelle an. Wenn dieses Attribut nicht vorhanden ist und die Definition (direkt oder indirekt) System.ValueType erweitert und die Definition nicht für System.Enum gilt, muss ein Werttyp definiert werden (§II.13). Andernfalls ist eine Klasse zu definieren (§II.11).
I.8.9.10 In ihrer unboxed Form erben Werttypen von keinem Typ. Boxed-Value-Typen erben direkt von System.ValueType, es sei denn, es handelt sich um Aufzählungen. In diesem Fall erben sie von System.Enum. Boxed-Value-Typen müssen versiegelt sein.
II.13 Unboxed-Werttypen werden nicht als Untertypen eines anderen Typs betrachtet, und es ist nicht gültig, die isinst-Anweisung (siehe Partition III) für Unboxed-Werttypen zu verwenden. Die isinst-Anweisung kann jedoch für Boxed-Value-Typen verwendet werden.
I.8.9.10 Ein Werttyp erbt nicht. Vielmehr definiert der in der Klassendefinition angegebene Basistyp den Basistyp des Box-Typs.
I.8.9.7 Werttypen unterstützen keine Schnittstellenverträge, die zugehörigen Box-Typen jedoch.
II.13 Werttypen müssen null oder mehr Schnittstellen implementieren, dies hat jedoch nur in ihrer Boxform eine Bedeutung (§II.13.3).
I.8.2.4 Schnittstellen und Vererbung werden nur für Referenztypen definiert. Während eine Werttypdefinition (§I.8.9.7) beide Schnittstellen angeben kann, die vom Werttyp und der Klasse (System.ValueType oder System.Enum) implementiert werden sollen, gelten diese nur für Werte in Kästchen .
II.13.1 Auf die nicht verpackte Form eines Werttyps wird mit dem Schlüsselwort valueetype gefolgt von einer Typreferenz verwiesen. Auf die Boxform eines Werttyps wird mit dem Schlüsselwort boxed gefolgt von einer Typreferenz verwiesen.
Hinweis: Die Angabe ist hier falsch, es gibt kein boxed
Schlüsselwort.
Ich denke, ein Teil der Verwirrung darüber, wie Werttypen zu erben scheinen, beruht auf der Tatsache, dass C # Casting-Syntax verwendet, um Boxen und Unboxing durchzuführen, was den Anschein erweckt, als würden Sie Casts ausführen, was nicht wirklich der Fall ist (obwohl das CLR löst eine InvalidCastException aus, wenn versucht wird, den falschen Typ zu entpacken.
(object)myStruct
in C # erstellt eine neue Instanz des Box-Typs des Werttyps; Es werden keine Casts ausgeführt. Ebenso wird (MyStruct)obj
in C # ein Box-Typ entpackt, der den Wertteil herauskopiert. Es werden keine Casts ausgeführt.
System.ValueType
Typs im CLR-Typsystem.