Warum ist String ein Referenztyp?

7

Warum ist string ein Referenztyp, obwohl er normalerweise primitiver Datentyp wie int, float oder double ist.

    
selvaraj 07.09.2010, 05:23
quelle

3 Antworten

11

Huch, diese Antwort wurde akzeptiert und dann habe ich sie geändert. Ich sollte wahrscheinlich die ursprüngliche Antwort an den unteren Rand einfügen, da dies vom OP akzeptiert wurde.

Neue Antwort

Aktualisieren : Hier ist die Sache. string absolut muss sich wie ein Referenztyp verhalten . Die Gründe dafür wurden bisher von allen Antworten berührt: Der string -Typ hat keine konstante Größe, es macht keinen Sinn, den gesamten Inhalt einer Zeichenkette von einer Methode in eine andere zu kopieren, sonst würden string[] -Arrays muss die Größe von themelves ändern - um nur einige zu nennen.

Aber Sie könnten definieren string als struct , das intern auf ein char[] -Array verweist, oder sogar einen char* -Zeiger und ein int für seine Länge, machen Sie es unveränderlich, und voila! , Sie hätten einen Typ, der sich wie ein Referenztyp verhält, aber technisch ein Werttyp ist.

Das wäre ziemlich albern, ehrlich gesagt. Wie Eric Lippert in einigen der Kommentare zu anderen Antworten darauf hingewiesen hat, ist die Definition eines solchen Werttyps im Grunde dasselbe wie die Definition eines Referenztyps. In fast jeder Hinsicht wäre es von einem auf die gleiche Weise definierten Referenztyp nicht zu unterscheiden.

Also die Antwort auf die Frage "Warum ist string ein Referenztyp?" ist im Grunde genommen: "Es Wert zu machen wäre einfach albern." Aber wenn das der einzige Grund ist, dann ist die logische Schlussfolgerung, dass string tatsächlich wie oben beschrieben als struct definiert werden konnte und es kein besonders gutes Argument gegen diese Wahl geben würde.

Allerdings sind Gründe, dass es besser ist, string a class als% struct zu machen, die mehr als rein intellektuell sind. Hier sind ein Paar, an das ich denken konnte:

Um das Boxen zu verhindern

Wenn string ein Werttyp wäre, dann müsste jedes Mal, wenn Sie es an eine Methode übergeben haben, die object erwartet, ein neues object erzeugt werden, wodurch der Heap aufgebläht würde und sinnlos wäre GC-Druck. Da Strings im Prinzip überall sind , wäre es ein großes Problem, sie zu haben, wenn man sie ständig boxt.

Für einen intuitiven Gleichheitsvergleich

Ja, string kann Equals überschreiben, unabhängig davon, ob es sich um einen Referenztyp oder -typ handelt. Aber wenn es ein Werttyp wäre, dann würde ReferenceEquals("a", "a") false zurückgeben! Dies liegt daran, dass beide Argumente eingerahmt und die Argumente mit Box nie erhalten würden habe gleiche Referenzen (soweit ich weiß).

Auch wenn es wahr ist, dass Sie einen Wertetyp definieren könnten, um genau wie einen Referenztyp zu verwenden, indem er aus einem einzelnen Referenztypfeld besteht, wäre es immer noch nicht genau das gleiche. Also behalte ich dies als den vollständigeren Grund, warum string ein Referenztyp ist: Sie könnten es zu einem Werttyp machen, aber dies würde es nur mit unnötigen Schwächen belasten.

Ursprüngliche Antwort

Es ist ein Referenztyp, weil nur Referenzen darauf herumgereicht werden.

Wenn es ein Werttyp wäre, dann würde jedes Mal, wenn Sie eine Zeichenfolge von einer Methode zu einer anderen übergeben, die gesamte Zeichenfolge kopiert werden *.

Da es ein Referenztyp ist, anstelle von String-Werten wie "Hallo Welt!" herumgereicht werden - "Hallo Welt!" ist übrigens 12 Zeichen, was bedeutet, dass es (mindestens) 24 Bytes Speicher benötigt - nur Referenzen zu diesen Strings werden weitergegeben. Das Übergeben einer Referenz ist viel billiger als das Übergeben jedes einzelnen Zeichens in einer Zeichenfolge.

Außerdem ist es wirklich nicht ein normaler primitiver Datentyp. Wer hat dir das gesagt?

* Eigentlich ist das nicht genau richtig. Wenn die Zeichenfolge intern ein char[] -Array enthält, wird der Inhalt der Zeichenfolge, solange der Array-Typ ein Referenztyp ist, tatsächlich nicht als Wert übergeben - nur der Verweis auf das Array wäre. Ich denke immer noch, dass dies im Grunde die richtige Antwort ist.

    
Dan Tao 07.09.2010, 05:24
quelle
18

Zusätzlich zu den Gründen von Dan:

Werttypen sind nach Definition solche Typen, die ihre Werte in sich selbst speichern, anstatt auf einen Wert anderswo zu verweisen. Deshalb werden Werttypen als "Werttypen" und Referenztypen als "Referenztypen" bezeichnet. Also ist Ihre Frage wirklich "Warum bezieht sich eine Zeichenkette auf ihren Inhalt und nicht einfach auf mit Inhalt?"

Das liegt daran, dass Werttypen die nette Eigenschaft haben, dass jede Instanz eines bestimmten Werttyps dieselbe Größe im Speicher hat.

Na und? Warum ist das eine schöne Eigenschaft? Angenommen, Zeichenfolgen waren Werttypen, die eine beliebige Größe haben könnten, und berücksichtigen Folgendes:

%Vor%

Was sind die ursprünglichen Inhalte dieses Arrays aus drei Strings? Für Werttypen gibt es kein "Null". Daher ist es sinnvoll, ein Array aus drei leeren Strings zu erstellen. Wie würde das in Erinnerung bleiben? Denken Sie ein bisschen darüber nach. Wie würdest du es tun?

Nehmen wir an, Sie sagen

%Vor%

Jetzt haben wir "", "Hallo" und "" im Array. Wo im Speicher ist das "Hallo"? Wie groß ist der Slot, der für mistrings [1] vergeben wurde? Der Speicher für das Array und seine Elemente muss irgendwo sein.

Damit bleibt der CLR die folgende Auswahl:

  • Größe ändern das Array jedes Mal, wenn Sie eines seiner Elemente ändern, kopieren Sie das gesamte Ding, das Megabyte in der Größe
  • sein könnte
  • verbieten das Erstellen von Arrays mit Werttypen unbekannter Größe
  • verbieten das Erstellen von Werttypen unbekannter Größe

Das CLR-Team wählte das letztere. Wenn Sie Strings zu Referenztypen machen, können Sie Arrays effizient erstellen.

    
Eric Lippert 07.09.2010 15:33
quelle
1

String ist ein Referenztyp, kein Werttyp. In vielen Fällen kennen Sie die Länge der Zeichenfolge und den Inhalt der Zeichenfolge. In solchen Fällen ist es einfach, den Speicher für die Zeichenfolge zuzuordnen. aber bedenke so etwas.

%Vor%

ist es nicht möglich, die Zuordnungsdetails für "s" in der Kompilierungszeit zu kennen. Der Benutzer gibt die Werte ein und alle eingegebenen Zeichenfolgen / Zeilen werden in den s gespeichert. Daher werden Zeichenfolgen im Heapspeicher gespeichert, sodass der Speicher neu zugewiesen wird, damit er in den Inhalt der Zeichenfolge s passt. Und der Verweis auf diese Zeichenfolge wird im Stapel gespeichert.

Um mehr zu erfahren, lesen Sie bitte: .net zero by petzold

Lesen: Garbage Collection von CLR Via C # für Zuordnungsdetails auf Stapel.

Bearbeiten: Console.WriteLine (); zu Console.ReadLine ();

    
Harsha 07.09.2010 06:02
quelle