2010-05-19 17 views
28

Dies ist vielleicht eine Follow-up-Frage über nullable types.Wo im Speicher sind Nullable-Typen gespeichert?

Wo genau sind Nullwerttypen (int? ...) im Speicher gespeichert? Zuerst dachte ich, es ist klar genug, wie Nullable<T> ist struct und das sind Werttypen. Dann fand ich Jon Skeet Artikel „Memory in .NET“, die sagt:

Beachten Sie, dass ein Werttyp Variable kann nie einen Wert von null haben - es keinen Sinn machen würde, als null ein ist Referenzart Konzept, was bedeutet, " Wert dieses Referenztyps Variable ist kein Verweis auf ein Objekt bei alle".

Ich bin ein wenig verwirrt nach dem Lesen dieser Aussage. Also lass uns sagen, ich habe int? a = null;. Wie int ist normalerweise ein Werttyp, ist es irgendwie in Struktur Nullable<T> im Stapel gespeichert (Ich habe "normal" verwendet, weil ich nicht weiß, was mit Werttyp passiert, wenn es NULL wird)? Oder irgendetwas anderes passiert hier - vielleicht in Haufen?

Antwort

67

First off, Nullable<int> ist nur eine Abkürzung für so etwas wie:

struct Nullable<T> 
{ 
    bool hasValue; 
    T value; 
} 

plus alle Konstruktoren, Accessoren und so weiter. Das ist alles, was es ist - ein Nullable-Int ist ein gewöhnlicher Int plus ein Flag, das angibt, ob der Int null ist oder nicht. Der ganze Rest ist Compiler Magie, die "Null" als gültigen Wert behandelt; Alles was "null" mit einem Nullable-Typ ist, macht Sie zu einer dieser Strukturen mit dem Flag false.

So jetzt, wo wir das aus dem Weg haben, ist Ihre Frage "wohin gehen sie in Erinnerung"? Sie gehen an die gleiche Stelle, an der andere Strukturen in Erinnerung bleiben: Wo die Laufzeit und der Compiler angesichts der Lebensdauer des Speichers der beste Ort sind.

Die meisten Strukturen gehen auf den Haufen. Jeder, der Ihnen sagt, dass "Strukturen immer auf den Stapel gehen", weiß nicht, worüber sie sprechen. Unsere Dokumentation sagt das nicht und es ist nicht wahr. Structs gehen nur in den temporären Speicherpool, auch "der Stapel" genannt, wenn es sich um lokale Variablen oder Provisorien handelt, und die lokalen Variablen sind keine geschlossenen äußeren Variablen einer anonymen Methode oder Lambda und die lokalen Variablen befinden sich nicht in einem Iterator Block. Alle anderen Strukturen gehen in unserer Implementierung auf den Heap.

Beachten Sie auch, dass es keinerlei Anforderung gibt, dass eine CLI-Implementierung "den Stapel" verwendet, um ihren temporären Pool zu erstellen. Der klassische JScript-Speichermanager speichert beispielsweise seinen temporären Pool auf dem Heap. (Obwohl die JScript-Laufzeit-Engine natürlich keine Implementierung der CLI ist, möchte ich nur darauf hinweisen, dass man eine verwaltete Laufzeit-Engine entwerfen kann, die keinerlei Benutzerdaten auf den "Stack" legt.) Logischerweise handelt es sich um eine Stack-Datenstruktur , aber diese Datenstruktur wird nicht auf "dem" Stapel gespeichert, es ist nur eine Stapelstruktur, die auf dem Heap zugewiesen ist.

Ich muss fragen: warum kümmert es dich? Die CLR verwaltet den Speicher in Ihrem Namen. Warum interessiert es dich, wo Nullable Typen gehen? Sie gehen lange genug dorthin, wo sie leben, um dir nützlich zu sein. du musst dir darüber keine Sorgen machen.

+6

Eine sehr einfache +1 von mir. Danke für die erschöpfende Antwort. Es interessiert mich, weil ich neugierig bin. Ich denke (naiv genug), dass es wertvolle Informationen gibt, um zu wissen, was tatsächlich hinter meinem Code passiert. Ich möchte nicht am Ende etwas kodieren, das weiß, was Magie ist. –

+2

@Ondrej, wenn Sie der Meinung sind, dass die Nullable Compiler-Unterstützung magisch ist, versuchen Sie, eine IEnumerable-Methode mit yield returns mit einem Lambda-Ausdruck zu schreiben, der eine Closure enthält. Öffnen Sie das resultierende Programm in ildasm und schauen Sie sich an, was der Compiler unter der Decke für Sie getan hat. –

+0

Ich habe allgemein gesprochen. Nicht, dass ich eigentlich denke, dass alles in der Programmierung eine Magie ist. Ich bin mir bewusst, dass es höchstwahrscheinlich schwer verständliche Codeabschnitte gibt, als dies der Fall ist. –

7

Siehe Eric's Kommentar darüber, wo Strukturen gespeichert sind. Es ist viel gründlicher (und korrekter) als was ich gepostet habe.

Die Funktionsweise ist so, dass die Nullable einen Booleschen Wert hat, der angibt, ob der Wert festgelegt wurde oder nicht. Technisch korrekt ist die Nullable (int, bool) usw. ist nicht wirklich null. Es hat einen Standardwert. Es ist nur so, dass der NULL-fähige Typ jetzt einen booleschen Wert hat, den Sie überprüfen können, und sehen, ob dieser Wert festgelegt wurde oder ob es nur der Standardwert ist. Die = und == sind außer Kraft gesetzt die entsprechenden Werte zu setzen, wenn null (und Wert), um es

MSDN-Link zu Nullables

Einen weiteren Link Zuordnung beschreibt, wie nullables arbeitet:
http://www.markzhou.com/blog/post/2010/01/27/Why-can-assign-e2809cnulle2809d-to-nullable-types.aspx

+4

Strukturen werden nicht immer auf dem Stapel gespeichert. Eine korrekte Anweisung lautet "lokale Variablen vom Struct-Typ, die keine äußeren Variablen einer anonymen Methode oder Lambda-Ausdrücke sind und die nicht in einem Iterator-Block sind, werden auf dem Stack in der Microsoft-Implementierung der Desktop-CLR gespeichert." Es ist nicht erforderlich, dass eine Datenstruktur namens "der Stapel" vorhanden ist oder dass alle Strukturen darauf gespeichert sind. Strukturen, die Felder einer Klasse oder Locals in einem Iteratorblock oder äußere Variablen sind, werden auf dem Heap gespeichert. –

+0

Wie immer, danke für die Klarstellung. – kemiller2002

2

Neben Kevins Antwort: Der Compiler kennt NULL-Typen und ändert einen ==null Check in einen Aufruf von ".HasValue".

3

nullables so tun, als nur null sein:

int? a = null; 
Debug.Assert((a == null) == (!a.HasValue)); 

Der Compiler in dieser Farce mitschuldig ist. Eine lustige Folge davon ist die folgende:

Nullable<double> b = new Nullable<double>(); 
Debug.Assert(b == null); //I'm null upon construction! 

Sie erhalten auch spezielle Boxen Unterstützung:

int? c = null; 
Object d = c; 
Debug.Assert(d == null); 
Debug.Assert(!c.HasValue); 
+0

Sie haben die meiste Magie von allen vergessen (eine, die Sie nicht mit Überlastung des Bedieners emulieren können): Bediener, der anhebt. –

Verwandte Themen