Sdílet prostřednictvím


Wert- und Verweistypen (Visual C# Express)

Aktualisiert: November 2007

Im Unterschied zu anderen Programmiersprachen, die Sie möglicherweise kennen, verfügt C# über zwei Datentypvarianten: Wert- und Referenztypen. Den Unterschied zu kennen, ist für die Leistung der Anwendung wichtig, oder falls Sie wissen möchten, wie C# Daten und Arbeitsspeicher verwaltet.

Wenn eine Variable mithilfe eines integrierten Basisdatentyps oder einer benutzerdefinierten Struktur deklariert wird, handelt es sich um einen Werttyp. Eine Ausnahme bildet der string-Datentyp, der ein Referenztyp ist.

Ein Werttyp speichert seinen Inhalt in dem Speicherbereich, der auf dem Stapel reserviert ist. In diesem Beispiel wird der Wert 42 in einem als Stapel bezeichneten Speicherbereich gespeichert:

int x = 42;

Wenn die Variable x den Gültigkeitsbereich verlässt, weil die Methode, in der sie definiert wurde, die Ausführung beendet hat, wird der Wert aus dem Stapel gelöscht.

Stapelverwendung ist effizient. Die begrenzte Lebensdauer von Werttypen macht sie allerdings weniger geeignet, wenn Daten von unterschiedlichen Klassen gemeinsam genutzt werden sollen.

Im Gegensatz dazu werden Referenztypen, wie die Instanz einer Klasse oder eines Arrays, in einem anderen Speicherbereich abgelegt, dem so genannten "Heap". Im folgenden Beispiel wird der erforderliche Speicherplatz für die zehn ganzen Zahlen des Arrays auf dem Heap bereitgestellt.

int[] numbers = new int[10];

Dieser Speicherplatz wird bei Beendigung der Methode nicht an den Heap zurückgegeben, sondern erst freigegeben, wenn die Garbage Collection von C# feststellt, dass er nicht länger benötigt wird. Der Aufwand beim Deklarieren von Referenztypen ist zwar größer, aber sie haben den Vorteil, dass sie für alle Klassen verfügbar sind.

Boxing und Unboxing

Die Konvertierung eines Werttyps in einen Referenztyp wird "Boxing" genannt. Beim Boxing einer Variablen wird eine Verweisvariable erstellt, die auf eine neue Kopie auf dem Heap zeigt Die Verweisvariable ist ein Objekt und kann deshalb alle Methoden verwenden, die ein Objekt erbt, zum Beispiel ToString(). Dies geschieht im folgenden Code:

int i = 67;                              // i is a value type
object o = i;                            // i is boxed
System.Console.WriteLine(i.ToString());  // i is boxed

Unboxing tritt bei Klassen auf, die zur Verwendung mit Objekten vorgesehen sind, zum Beispiel die Verwendung einer ArrayList zum Speichern von ganzen Zahlen. Wenn Sie im ArrayList-Objekt eine ganze Zahl speichern, wird sie geschachtelt. Wenn Sie eine ganze Zahl abrufen, muss sie mittels Unboxing konvertiert werden.

System.Collections.ArrayList list = 
    new System.Collections.ArrayList();  // list is a reference type
int n = 67;                              // n is a value type
list.Add(n);                             // n is boxed
n = (int)list[0];                        // list[0] is unboxed

Leistungsaspekte

Das folgende Thema sollte genauer betrachtet werden. Wenn Daten als Werttypparameter an eine Methode übergeben werden, wird im Stapel von jedem einzelnen Parameter eine Kopie erstellt. Wenn der fragliche Parameter ein großer Datentyp ist, z. B. eine benutzerdefinierte Struktur mit vielen Elementen, oder die Methode häufig verwendet wird, wirkt sich dies unter Umständen auf die Leistung aus.

In solchen Situationen ist es ggf. besser, mithilfe des ref-Schlüsselwortes einen Verweis an den Typ zu übergeben. Dabei handelt es sich um das C#-Äquivalent zu der C++-Methode, einer Funktion einen Zeiger auf eine Variable zu übergeben. Wobei in der C++-Version die Methode den Inhalt der Variablen ändern kann, der möglicherweise nicht immer sicher ist. Der Programmierer muss dabei zwischen Sicherheit und Leistung das richtige Maß finden.

int AddTen(int number)  // parameter is passed by value
{
    return number + 10;
}
void AddTen(ref int number)  // parameter is passed by reference
{
    number += 10;
}

Das out-Schlüsselwort ist dem ref-Schlüsselwort ähnlich, jedoch teilt es dem Compiler mit, dass die Methode dem Parameter einen Wert zuweisen muss, damit kein Kompilierungsfehler auftritt.

void SetToTen(out int number)
{
    // If this line is not present, the code will not compile.
    number = 10;
}

Siehe auch

Konzepte

Einführung in C#

Integrierte Datentypen (Visual C# Express)

Arrays und Auflistungen (Visual C# Express)

Referenz

Werttypen (C#-Referenz)

Verweistypen (C#-Referenz)

Boxing und Unboxing (C#-Programmierhandbuch)