Ein tiefer Tauchgang: Wert- und Referenztypen in .Net

Typen in Microsoft .Net können entweder Werttypen oder Referenztypen sein. Während Werttypen im Allgemeinen im Stapel gespeichert werden, werden Referenztypen im verwalteten Heap gespeichert.

Ein Werttyp leitet sich von System.ValueType ab und enthält die Daten in seiner eigenen Speicherzuordnung. Mit anderen Worten, Variablen oder Objekte oder Werttypen haben eine eigene Kopie der Daten.

Ein Referenztyp erweitert unterdessen System.Object und zeigt auf eine Stelle im Speicher, die die tatsächlichen Daten enthält. Sie können sich einen Referenztyp vorstellen, der einem Zeiger ähnelt, der beim Zugriff implizit dereferenziert wird. Zu den von C # unterstützten integrierten Referenztypen gehören: Objekt, Zeichenfolge und Dynamik. Alle grundlegenden Datentypen, Boolean, Date, structs und enums, sind Beispiele für Werttypen. Beispiele für Referenztypen sind: Zeichenfolgen, Arrays, Objekte von Klassen usw. Um Referenztypen in C # zu erstellen, können Sie die folgenden Schlüsselwörter verwenden: Klasse, Schnittstelle und Delegat.

Beachten Sie, dass Sie im Gegensatz zu einem Referenztyp weder einen Werttyp ableiten noch einem Werttyp einen Nullwert direkt zuweisen können. Sie können einem Werttyp nur dann einen Nullwert zuweisen, wenn Sie nullfähige Typen nutzen - eine Funktion, die den neueren Versionen von .Net Framework hinzugefügt wurde. Wenn ein Werttyp in einen anderen kopiert wird, wird der Wert kopiert. Daher können Sie die Werte in ihnen unabhängig vom anderen manipulieren - eine Änderung in einem wirkt sich nicht auf den anderen aus. Im Gegenteil, wenn Sie einen Referenztyp in einen anderen kopieren, wird die Referenz kopiert. Wenn Sie einen von ihnen ändern, ist auch der andere betroffen. Wenn beispielsweise eine der Referenzen auf null gesetzt ist, wird die andere ebenfalls null.

Lagerorte

Die CLR speichert Objekte an drei Arten von Speicherorten - den Registern, dem Stapel oder dem verwalteten Heap. Während die kurzlebigen Objekte in Registern oder im Stapel gespeichert sind, werden die langlebigen Objekte im Heap gespeichert. Wie bereits erwähnt, werden Werttypen im Allgemeinen im Stapel gespeichert.

Es ist ein weit verbreitetes Missverständnis, dass Werttypen immer im Stapel gespeichert werden. Ich würde eher sagen, dass Werttypen im Stapel gespeichert werden können , wenn die Variable entweder eine temporäre Variable oder eine lokale Variable ist und der JIT-Compiler beschließt, den Wert nicht zu registrieren. Im Wesentlichen hängt der tatsächliche Speicherort eines Werttyps von der Implementierung des JIT-Compilers ab. Beachten Sie, dass ein Werttyp in einem Stapelrahmen, im CPU-Register oder sogar im Heapspeicher gespeichert werden kann, wenn der Werttyp in einem Objekt enthalten ist, dh wenn er Teil eines Referenztyps ist. Im Gegenteil, Referenztypen werden im GC-Heap gespeichert. Die Referenz wird in einem Stapel gespeichert, während das Objekt im Heap zugewiesen wird.

Instanzen oder Referenzen eines Werttyps werden im Stapel, im Register oder im Heap gespeichert, je nachdem, ob die Lebensdauer der Instanz oder der Referenz kurzlebig oder langlebig ist. Ein Werttyp kann sich auf dem Stapel befinden, wenn es sich um lokale Variablen handelt, und im verwalteten Heap, wenn es sich um Felder einer Klasse handelt, dh wenn sie zu einem Referenztyp gehören oder Teil eines Referenztyps sind.

Wertübergabe und Referenzübergabe

Die folgende Codeliste zeigt, wie Sie eine Variable nach Wert an eine Methode übergeben können.

 static void Increment(int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Beachten Sie, dass Sie mit dem Schlüsselwort ref einen Werttyp als Referenz auf eine Methode übergeben können. Die folgende Codeliste veranschaulicht dies.

static void Increment(ref int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(ref x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Wenn der obige Code ausgeführt wird, wird in der Konsole die Meldung "Der Wert von x ist: 2" angezeigt.

Boxen und Unboxen

Die Konvertierung eines Werttyps in einen Referenztyp wird als Boxing bezeichnet. Unboxing ist genau das Gegenteil - es ist definiert als der Prozess der Konvertierung eines Referenztyps in einen Werttyp. Das folgende Codefragment veranschaulicht das Ein- und Auspacken in C #.

int i = 100;

Object obj = i; //Boxing

i = (int) obj; //Unboxing