次の方法で共有


System.String.Intern メソッド

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

共通言語ランタイムは、一意の文字列値ごとに 1 つの参照を保持する、 インターン プールと呼ばれるテーブルを保持します。 Internメソッドは、インターン プールを使用して、strの値と等しい文字列を検索します。 そのような文字列が存在しない場合は、 str への参照がプールに追加され、その参照が返されます。 (これに対し、要求された文字列がインターン プールに存在しない場合、 IsInterned(String) メソッドは null 参照を返します)。

インターンプールは、ランタイムによって文字列ストレージを節約するために使用されます。 ただし、文字列リテラルの自動インターンは保証されません。アセンブリのコンパイルと実行方法によっては、一部のリテラルがプールに追加されない場合があります。

次の例では、文字列 s1 の値は "MyTest" です。 System.Text.StringBuilder クラスは、s1と同じ値を持つ新しい文字列オブジェクトを生成します。 その文字列への参照が s2に割り当てられます。 Intern メソッドは、s2と同じ値を持つ文字列を検索します。 s1が既にインターンされている場合(たとえば、アセンブリが文字列リテラルのインターンを必要とする場合)、メソッドはs1と同じ参照を返します。この参照はs3に割り当てられ、s1s3が等しいことを確認します。 それ以外の場合は、s2 用に新しいインターン(永続化された)エントリが作成され、s3 に割り当てられ、s1s3 は等しくないと比較されます。 どちらの場合も、 s1s2 は異なるオブジェクトを参照するため、等しくない値を比較します。

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列挙メンバーは、アセンブリを文字列リテラルのインターンを必要としないものとしてマークします。 既定では、C# コンパイラはパフォーマンスを向上させるために各アセンブリに CompilationRelaxationsAttribute フラグを持つNoStringInterningを出力します。つまり、文字列リテラルがインターン プールに追加される保証はありません。 NoStringInterning属性を使用して、アセンブリのCompilationRelaxationsAttributeをカスタマイズできます。

ネイティブ AOT を使用してアプリを発行する場合、NoStringInterningをオフにすることはサポートされていません。 ネイティブ AOT では、文字列リテラルがインターン プールに追加されるとは限らないので、 Intern ソース コード内のリテラルと思われる文字列の一致が見つからない可能性があります。