2009-03-31 1 views
1

Ist es aufgrund von String-Pooling von CLR oder von der GetHashCode() -Methode beider Strings den gleichen Wert zurückgegeben?Liegt das am String-Pooling nach CLR oder an der Methode GetHashCode()?

string s1 = "xyz"; 
string s2 = "xyz"; 
Console.WriteLine(" s1 reference equals s2 : {0}", object.ReferenceEquals(s1, s2)); 

Console schreibt: "s1 Referenz gleich s2: True"

Ich glaube, es ist nicht wegen der GetHashCode() gibt denselben Wert für beide String-Instanz. Weil ich mit dem benutzerdefinierten Objekt getestet habe und die GetHasCode() -Methode überschrieben habe, um jedes Mal eine einzelne Konstante zurückzugeben. Die zwei separaten Instanzen dieses Objekts sind in der Referenz nicht identisch.

Bitte lassen Sie mich wissen, was passiert hinter der Szene.

dank 123Developer

Antwort

14

Es klingt wie string interning - ein Verfahren, nur eine Kopie einer Zeichenfolge zu speichern. Es erfordert, dass Strings in der Sprache, mit der Sie zu tun haben, ein unveränderlicher Typ ist, und .Net erfüllt dies und verwendet String-Interning.

Beim String-Interning wird ein String "xyz" im internen Pool gespeichert, und wenn Sie intern "xyz" sagen, referenziert er den Eintrag im Pool. Dies kann Speicherplatz sparen, indem die Zeichenfolge nur einmal gespeichert wird. Also wird ein Vergleich von "xyz" == "xyz" als [Zeiger auf 34576] == [Zeiger auf 34576] interpretiert, was wahr ist.

+0

Beat mich um 32 Sekunden. –

+0

+1 Vielleicht wäre es hilfreich, den Artikel ein wenig in Ihrer Antwort zu zitieren. –

6

Dies ist definitiv wegen String Interning. Hash-Codes sind nie berechnet beim Vergleich von Referenzen mit object.ReferenceEquals.

Vom # spec C, Abschnitt 2.4.4.5:

Jeder Stringliteral nicht notwendigerweise in einer Instanz neuen Zeichenfolge führen. Wenn zwei oder mehr Zeichenfolgen Literale, die entsprechend dem Zeichenfolgengleichheitsoperator (§7.9.7) entsprechen, in demselben Programm angezeigt werden, beziehen sich diese Zeichenfolgenliterale auf die gleiche Zeichenfolgeninstanz.

Beachten Sie, dass String konstanter Ausdrücke als Literale in diesem Fall zu zählen, so:

string x = "a" + "b"; 
string y = "ab"; 

Es ist garantiert, dass x und y auf das gleiche Objekt beziehen zu (das heißt, sie sind die gleichen Bezugszeichen).

Wenn die Spezifikation "Programm" übrigens sagt, bedeutet es wirklich "Assembly". Das Verhalten gleicher Strings in verschiedenen Assemblys hängt von Dingen wie CompilationRelaxations.NoStringInterning und der genauen CLR-Implementierungs- und Ausführungszeit-Situation ab (z. B. ob die Assembly ngen ist oder nicht).

+0

@Jon Zeichenfolge x = "a" + "b"; ist nichts außer string x = "ab"; Es wäre zur Kompilierzeit selbst passiert, oder? Können wir sagen, dass die frühere Syntax nur zur besseren Lesbarkeit existiert? – 123Developer

+0

@ 123Developer: Es ist mehr als nur Lesbarkeit - das "a" könnte tatsächlich SomeClass.StringConstant sein, das wäre ziemlich schlecht im Quellcode zu kopieren. Aber ja, sie sind genau gleichwertig. Die Verkettung wird zur Kompilierungszeit durchgeführt. –

0

Stimmen Sie absolut mit Tom's answer überein ...

Auszug aus CIL Specification(Seite 126):

Die CLI garantiert, dass das Ergebnis der zwei ldstr Anweisungen zu beziehen zwei Metadaten-Token, die die gleiche Folge von Zeichen haben, kehren genau die dasselbe String-Objekt (ein Prozess, der als "String Interning" bekannt ist).

4

Es ist vergleichbar mit String-Pooling, aber es ist nicht zur Laufzeit, sondern zur Kompilierzeit getan.

Ein beliebiges Zeichenfolgenliteral in einer Assembly existiert nur einmal. Der Compiler verwendet für alle Vorkommen des String-Literals "xyz" die gleiche Konstantenzeichenfolge. Da Strings unveränderlich sind (Sie können den Wert einer String-Instanz niemals ändern), kann der Compiler die gleiche String-Instanz für separate String-Referenzen verwenden.

Wenn Sie stattdessen eine Zeichenfolge zur Laufzeit erstellen, erhalten Sie eine separate Instanz:

string s1 = "xyz"; 

string s2 = "xy"; 
s2 += "z"; 

Console.WriteLine("s1 ref = s2 : {0}", object.ReferenceEquals(s1, s2)); 

Ausgang:

s1 ref = s2 : False 
0

Zeichenfolge Internierung nichts damit zu tun hat.

Ich wäre sehr überrascht zu finden, dass .NET/C# -Compiler Intern implizit aufruft, Es dauert zu viel Belastung für die CPU, um zur Laufzeit auf übereinstimmende Zeichenfolge zu überprüfen.

+0

Sie sind falsch. Operatoren sind nicht virtuell. Die Methode object.ReferenceEquals ruft nicht den Operator == (string, string), sondern den Operator == (object, object) auf. – Guffa