Mit zwei grundlegenden Punktem über das System der Typen in .NET Framework sollten Sie vertraut sein:
Es unterstützt das Prinzip der Vererbung. Typen können von anderen Typen abgeleitet werden, die als Basistypen bezeichnet werden. Der abgeleitete Typ erbt (mit einigen Beschränkungen) die Methoden, Eigenschaften und anderen Member des Basistyps. Der Basistyp kann wiederum von einem anderen Typ abgeleitet sein. In diesem Fall erbt der abgeleitete Typ die Member beider Basistypen in der Vererbungshierarchie. Alle Typen, einschließlich integrierter numerischer Typen, z. B. System..::.Int32 (C#-Schlüsselwort: int), werden letztendlich von einem einzelnen Basistyp abgeleitet, nämlich System..::.Object (C#-Schlüsselwort: object). Diese einheitliche Typhierarchie wird als Allgemeines Typsystem (CTS) bezeichnet. Weitere Informationen zur Vererbung in C# finden Sie unter Vererbung (C#-Programmierhandbuch).
Jeder Typ im CTS ist als Werttyp oder Referenztyp definiert. Dies betrifft auch alle benutzerdefinierten Typen in der .NET Framework-Klassenbibliothek und Ihre eigenen benutzerdefinierten Typen. Typen, die Sie mithilfe des struct-Schlüsselworts definieren, sind Werttypen. Alle integrierten numerischen Typen sind structs. Typen, die Sie mithilfe des class-Schlüsselworts definieren, sind Referenztypen. Für Referenztypen und Werttypen gelten unterschiedliche Kompilierzeitregeln und ein anderes Laufzeitverhalten.
In der folgenden Abbildung wird die Beziehung zwischen Werttypen und Referenztypen im CTS dargestellt.
Werttypen und Referenztypen im CTS
.png)
Hinweis: |
|---|
Wie Sie sehen, sind die alle am häufigsten verwendeten Typen im System-Namespace organisiert. Jedoch ist es für den Namespace, in dem ein Typ enthalten ist, unerheblich, ob es sich um einen Werttyp oder einen Referenztyp handelt. |
Werttypen
Werttypen werden von System..::.ValueType abgeleitet, was wiederum von System..::.Object abgeleitet wird. Typen, die von System..::.ValueType abgeleitet werden, weisen ein besonderes Verhalten in der CLR auf. Werttypvariablen enthalten die zugehörigen Werte direkt, d. h., der Speicher wird inline in dem Kontext reserviert, in dem die Variable deklariert ist. Für Werttypvariablen erfolgt keine getrennte Heapreservierung oder Garbage Collection.
Zwei Kategorien von Werttypen sind verfügbar: struct und enum.
Die integrierten numerischen Typen sind Strukturen und verfügen über Eigenschaften und Methoden, auf denen Sie zugreifen können:
|
// Static method on type Byte.
byte b = Byte.MaxValue();
|
Sie deklarieren diese jedoch und weisen ihnen Werte zu, als wären es einfache, nicht aggregierte Typen:
|
byte num = 0xA;
int i = 5;
char c = 'Z';
|
Werttypen sind versiegelt (sealed). Dies bedeutet z. B., dass Sie keinen Typ von System..::.Int32 ableiten können und dass eine Struktur nicht von einer benutzerdefinierten Klasse oder Struktur erben kann, weil eine Struktur nur von System..::.ValueType erben kann. Eine Struktur kann jedoch eine oder mehrere Schnittstellen implementieren. Sie können einen Strukturtyp in einen Schnittstellentyp umwandeln. Dadurch wird eine Boxing-Operation gestartet, mit der die Struktur von einem Referenztypobjekt im verwalteten Heap umschlossen wird. Boxing-Operationen werden auch ausgeführt, wenn Sie einen Werttyp an eine Methode übergeben, die System..::.Object als Eingabeparameter akzeptiert. Weitere Informationen finden Sie unter Boxing und Unboxing (C#-Programmierhandbuch).
Sie können das struct-Schlüsselwort verwenden, um eigene benutzerdefinierte Werttypen zu erstellen. In der Regel wird eine Struktur als Container für einen kleinen Satz verwandter Variablen verwendet, wie im folgenden Beispiel dargestellt:
|
public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
|
Weitere Informationen über Strukturen finden Sie unter Strukturen (C#-Programmierhandbuch). Weitere Informationen über Werttypen im .NET Framework finden Sie unter Werttypen im allgemeinen Typsystem.
Die andere Kategorie von Werttypen ist die enum. Eine Enumeration definiert einen Satz benannter ganzzahliger Konstanten. So enthält z. B. die System.IO..::.FileMode-Enumeration in der .NET Framework-Klassenbibliothek einen Satz benannter ganzzahliger Konstanten, die festlegen, wie eine Datei geöffnet werden soll. Die Definition erfolgt wie im folgenden Beispiel:
|
public enum FileMode
{
CreateNew = 1,
Create = 2,
Open = 3,
OpenOrCreate = 4,
Truncate = 5,
Append = 6,
}
|
Die Create-Konstante besitzt den Wert 2. Der Name ist jedoch für Personen, die den Quellcode lesen, viel aussagekräftiger. Aus diesem Grund ist es besser, an Stelle von Konstantenliteralen Enumerationen zu verwenden.
Alle Enumerationen erben von System..::.Enum, was wiederum von System..::.ValueType erbt. Alle Regeln, die für Strukturen gelten, gelten auch für Enumerationen. Weitere Informationen über Enumerationen finden Sie unter Enumerationstypen (C#-Programmierhandbuch).
Referenztypen
Ein Typ, der als Klasse, Delegat, Array oder Schnittstelle definiert ist, ist ein Referenztyp. Wenn Sie eine Variable für einen Referenztyp deklarieren, enthält die Variable zunächst den Wert NULL, bis Sie explizit eine Instanz des Objekts mithilfe des Operators new erstellen oder ihr ein Objekt zuweisen, das anderer Stelle mithilfe des folgenden Operators erstellt wurde: new, as shown in the following example:.
|
MyClass mc = new MyClass();
MyClass mc2 = mc;
|
Eine Schnittstelle muss zusammen mit einem Klassenobjekt initialisiert werden, von dem sie implementiert wird. Wenn IMyInterface von MyClass implementiert wird, erstellen Sie eine Instanz von IMyInterface, wie im folgenden Beispiel gezeigt:
|
IMyInterface iface = new MyClass();
|
Beim Erstellen des Objekts wird der Speicher im verwalteten Heap zugewiesen. Die Variable enthält lediglich einen Verweis auf den Speicherort des Objekts. Für Typen im verwalteten Heap ist ein Overhead erforderlich, wenn sie zugewiesen werden und wenn sie von der automatischen Speicherverwaltungsfunktion der CLR freigegeben werden, was als Garbage Collection bezeichnet wird. Die Garbage Collection ist jedoch auch stark optimiert. In den meisten Szenarien führt sie nicht zu einem Leistungsproblem. Weitere Informationen über die Garbage Collection finden Sie unter Automatische Speicherverwaltung.
Alle Arrays sind Referenztypen, selbst wenn ihre Elemente Werttypen sind. Arrays werden implizit von der System..::.Array-Klasse abgeleitet. Sie deklarieren und verwenden Sie diese jedoch mit der vereinfachten, von C# bereitgestellten Syntax, wie im folgenden Beispiel dargestellt:
|
// Declare and initialize an array of integers.
int[] nums = { 1, 2, 3, 4, 5 };
// Access an instance property of System.Array.
int len = nums.Length;
|
Referenztypen bieten volle Vererbungsunterstützung. Wenn Sie eine Klasse erstellen, können Sie von einer anderen Schnittstelle oder Klasse erben, die nicht als versiegelt definiert ist. Andere Klassen können von Ihrer Klasse erben und die virtuellen Methoden überschreiben. Weitere Informationen zum Erstellen eigener Klassen finden Sie unter Klassen und Strukturen (C#-Programmierhandbuch). Weitere Informationen zur Vererbung und zu virtuellen Methoden finden Sie unter Vererbung (C#-Programmierhandbuch).