Método System.String.Intern

Observação

Este artigo fornece observações complementares à documentação de referência para esta API.

O runtime da linguagem comum mantém uma tabela, chamada intern pool, que contém uma única referência para cada valor único de cadeia. O Intern método utiliza o pool de estagiários para procurar uma cadeia igual ao valor de str. Se tal cadeia não existir, uma referência a str é adicionada ao pool, e essa referência é devolvida. (Por outro lado, o IsInterned(String) método retorna uma referência nula se a cadeia de caracteres solicitada não existir no pool de estagiários.)

O pool de internos pode ser usado pelo runtime para poupar armazenamento em cadeia. No entanto, a internação automática dos literais da string não é garantida—dependendo de como a assembly foi compilada e executada, alguns literais podem não ser adicionados ao pool.

No exemplo seguinte, a cadeia s1 tem o valor "MyTest". A System.Text.StringBuilder classe gera um novo objeto string que tem o mesmo valor que s1. Uma referência a essa cadeia de caracteres é atribuída a s2. O Intern método procura uma cadeia de caracteres que tenha o mesmo valor que s2. Se s1 já tivesse sido internado em memória (por exemplo, porque a montagem requer internamento literal de string), o método retorna a mesma referência de s1, que é depois atribuída a s3, e s1 e s3 são comparados como iguais. Caso contrário, uma nova entrada internada é criada para s2 e atribuída a s3, e s1 e s3 não são iguais. Em qualquer dos casos, s1 e s2 são desiguais porque se referem a objetos diferentes.

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.

Considerações sobre desempenho

Se você estiver tentando reduzir a quantidade total de memória que seu aplicativo aloca, lembre-se de que a introdução de uma cadeia de caracteres tem dois efeitos colaterais indesejados. Primeiro, a memória alocada para objetos internados String provavelmente não será liberada até que o Common Language Runtime (CLR) seja encerrado. O motivo é que a referência do CLR ao objeto interned String pode persistir depois que seu aplicativo, ou até mesmo seu domínio de aplicativo, for encerrado. Em segundo lugar, para inserir uma cadeia de caracteres, deve primeiro criar a cadeia de caracteres. A memória usada pelo objeto String ainda deve ser alocada, mesmo que a memória eventualmente seja gerida pelo coletor de lixo.

O CompilationRelaxations.NoStringInterning membro de enumeração marca um assembly como não exigindo internação de literais de strings. Por defeito, o compilador C# emite a CompilationRelaxationsAttribute com a NoStringInterning flag em cada assembly para melhor desempenho, o que significa que os literais de string não têm a garantia de serem adicionados ao intern pool. Podes personalizar NoStringInterning numa montagem usando o CompilationRelaxationsAttribute atributo.

Quando publicas uma aplicação usando AOT nativo, desligar NoStringInterning não é suportado. Com AOT nativo, os literais de string não são garantidos para serem adicionados ao pool de internos, por isso Intern pode não encontrar correspondência para uma string que pareça ser literal no código-fonte.