8

2 番目の ReferenceEquals 呼び出しは false を返します。s4 の文字列がインターンされないのはなぜですか? (文字列連結に対する StringBuilder の利点については気にしません。)

string s1 = "tom";
string s2 = "tom";


Console.Write(object.ReferenceEquals(s2, s1)); //true

string s3 = "tom";
string s4 = "to";
s4 += "m";

Console.Write(object.ReferenceEquals(s3, s4)); //false

私がするときString.Intern(s4);、私はまだ偽になります。

ここでは、s3 と s4 の両方がインターンされていますが、それらの参照は等しくありませんか?

string s3 = "tom";
string s4 = "to";
s4 += "m";
String.Intern(s4);

Console.WriteLine(s3 == s4); //true
Console.WriteLine(object.ReferenceEquals(s3, s4)); //false
Console.WriteLine(string.IsInterned(s3) != null);  //true (s3 is interned)
Console.WriteLine(string.IsInterned(s4) != null);  //true (s4 is interned)
4

6 に答える 6

17

の文字列s4はインターンされています。ただし、 を実行するs4 += "m";と、値が文字列リテラルではなく文字列連結操作の結果であるため、インターンされない新しい文字列が作成されます。その結果、s3s4は、2 つの異なるメモリ位置にある 2 つの異なる文字列インスタンスです。

文字列インターンの詳細については、ここを参照してください。具体的には、最後の例を参照してください。を行うString.Intern(s4)と、実際に文字列をインターンしていますが、これらの 2 つのインターンされた文字列の間で参照等価性テストをまだ実行していません。メソッドはインターンされた文字列を返すため、次のString.Internようにする必要があります。

string s1 = "tom";
string s2 = "tom";

Console.Write(object.ReferenceEquals(s2, s1)); //true 

string s3 = "tom";
string s4 = "to";
s4 += "m";

Console.Write(object.ReferenceEquals(s3, s4)); //false

string s5 = String.Intern(s4);

Console.Write(object.ReferenceEquals(s3, s5)); //true
于 2010-04-24T23:44:27.257 に答える
3

文字列は不変です。これは、その内容を変更できないことを意味します。

内部的に行う場合s4 += "m";、CLR は元の文字列と追加部分を含むメモリ内の別の場所に文字列をコピーします。

MSDN 文字列リファレンスを参照してください。

于 2010-04-24T23:43:30.503 に答える
2

まず第一に、不変文字列についてこれまでに書かれたことはすべて正しいです。しかし、書かれていない重要なことがいくつかあります。コード

string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true

"tom"実際には「True」と表示されますが、CLR は C# コンパイラ属性を無視し (「C# 経由の CLR」ブックを参照) 、ヒープに1 つの文字列のみを配置するため、いくつかの小さなコンパイラの最適化またはここに似ているためです。

次に、次の行で状況を修正できます。

s3 = String.Intern(s3);
s4 = String.Intern(s4);
Console.Write (object.ReferenceEquals (s3, s4)); //true

関数String.Internは、文字列のハッシュ コードを計算し、内部ハッシュ テーブルで同じハッシュを検索します。これを見つけたので、既存のStringオブジェクトへの参照を返します。文字列が内部ハッシュ テーブルに存在しない場合、文字列のコピーが作成され、ハッシュが計算されます。文字列はハッシュ テーブルによって参照されるため、ガベージ コレクターは文字列のメモリを解放しません。

于 2010-04-25T00:16:22.200 に答える
1

C# では、各文字列は個別のオブジェクトであり、編集できません。それらへの参照を作成していますが、各文字列は異なります。動作は一貫しており、理解しやすいです。

StringBuilder新しいインスタンスを作成せずに文字列を操作するクラスを調べることをお勧めしますか? 文字列でやりたいことには十分なはずです。

于 2010-04-24T23:44:52.320 に答える