次の方法で共有


System.String.Intern メソッド

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

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

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

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

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.

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

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

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