次の方法で共有


System.String.Intern メソッド

この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。

共通言語ランタイムは、プログラムで宣言またはプログラムによって作成された各一意のリテラル文字列への 1 つの参照を含む、インターン プールと呼ばれるテーブルをメインすることで、文字列ストレージを節約します。 したがって、特定の値を持つリテラル文字列のインスタンスは、システム内に 1 回だけ存在します。

たとえば、同じリテラル文字列を複数の変数に割り当てると、ランタイムは、インターン プールからリテラル文字列への同じ参照を取得し、各変数に割り当てます。

このメソッドでは Intern 、インターン プールを使用して、値 strと等しい文字列を検索します。 このような文字列が存在する場合は、インターン プール内の参照が返されます。 文字列が存在しない場合は、参照が str インターン プールに追加され、その参照が返されます。

次の例では、"MyTest" の値を持つ文字列 s1 は、プログラム内のリテラルであるため、既に強制収容されています。 このクラスは System.Text.StringBuilder 、s1 と同じ値を持つ新しい文字列オブジェクトを生成します。 その文字列への参照が s2 に割り当てられます。 このメソッドは Intern 、s2 と同じ値を持つ文字列を検索します。 このような文字列が存在するため、メソッドは s1 に割り当てられているのと同じ参照を返します。 その後、その参照が s3 に割り当てられます。 参照 s1 と s2 は、異なるオブジェクトを参照するため、等しくない比較を行います。参照 s1 と s3 は、同じ文字列を参照しているため、等しく比較されます。

string s1 = "MyTest"; 
string s2 = new StringBuilder().Append("My").Append("Test").ToString(); 
string s3 = String.Intern(s2); 
Console.WriteLine((Object)s2==(Object)s1); // Different references.
Console.WriteLine((Object)s3==(Object)s1); // The same reference.
let s1 = "MyTest"
let s2 = StringBuilder().Append("My").Append("Test").ToString()
let s3 = String.Intern s2
printfn $"{s2 :> obj = s1 :> obj}" // Different references.
printfn $"{s3 :> obj = s1 :> obj}" // The same reference.
Dim s1 As String = "MyTest" 
Dim s2 As String = New StringBuilder().Append("My").Append("Test").ToString() 
Dim s3 As String = String.Intern(s2) 
Console.WriteLine(CObj(s2) Is CObj(s1))      ' Different references.
Console.WriteLine(CObj(s3) Is CObj(s1))      ' The same reference.

このメソッドをメソッドと比較します IsInterned

次の例では、変数str1String.Empty参照が割り当てられ、値が文字列に変換されたオブジェクトを変換StringBuilderした後にString.Emptyメソッドを呼び出Internすことによって返される参照がString.Empty変数str2に割り当てられます。 次に、参照が格納 str1 され、 str2 等しいかどうかを比較します。 str1str2 が等しい。

string str1 = String.Empty;
string str2 = String.Empty;

StringBuilder sb = new StringBuilder().Append(String.Empty);
str2 = String.Intern(sb.ToString());

if ((object)str1 == (object)str2)
    Console.WriteLine("The strings are equal.");
else
    Console.WriteLine("The strings are not equal.");
let str1 = String.Empty
let str2 = String.Empty

let sb = StringBuilder().Append String.Empty
let str3 = String.Intern(string sb)

if (str1 :> obj) = (str3 :> obj) then
    printfn "The strings are equal."
else
    printfn "The strings are not equal."
Dim str1 As String = String.Empty
Dim str2 As String = String.Empty

Dim sb As StringBuilder = New StringBuilder().Append(String.Empty)
str2 = String.Intern(sb.ToString())

If CObj(str1) Is CObj(str2) Then
    Console.WriteLine("The strings are equal.")
Else
    Console.WriteLine("The strings are not equal.")
End If

パフォーマンスに関する考慮事項

アプリケーションが割り当てるメモリの総量を減らそうとしている場合は、文字列をインターンすると 2 つの望ましくない副作用があることに注意してください。 まず、共通言語ランタイム (CLR) が終了するまで、インターンオブジェクト String に割り当てられたメモリは解放されない可能性があります。 その理由は、CLR の強制オブジェクトStringへの参照は、アプリケーションの終了後、またはアプリケーションが終了した後も保持メイン。 次に、文字列をインターンするには、まず文字列を作成する必要があります。 オブジェクトによって String 使用されるメモリは、メモリが最終的にガベージ コレクションされる場合でも、引き続き割り当てる必要があります。

列挙メンバーは CompilationRelaxations.NoStringInterning 、文字列リテラルのインターンを必要としないアセンブリとしてマークします。 属性を使用してアセンブリにCompilationRelaxationsAttribute適用NoStringInterningできます。 また、Ngen.exe (ネイティブ イメージ ジェネレーター) を使用して実行時の前にアセンブリをコンパイルする場合、文字列はモジュール間で保持されません。