奇怪的字符串文字比较
深入了解C#,我遇到了一个与对象引用相等的小问题(奇怪)。 我说我有两个字符串:
String a = "Hello world!"; String b = "Bonjour le monde"; bool equals = ReferenceEquals(a, b); // ******************* (1) b = "Hello world!"; equals = ReferenceEquals(a, b); // ******************* (2)
(1)
是false
,这是预期的。 ReferenceEquals 文档说
ReferenceEquals比较实例
但是之后:
- 为什么(2)返回
true
? - 字符串
a
和b
不是同一个对象是吗? 如果是,那么它们是如何变得相同的,因为我从未明确地做过a=b
这是因为字符串实习 。
公共语言运行库通过维护一个名为intern pool的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。 因此,具有特定值的文字字符串实例仅在系统中存在一次。
例如,如果将相同的文字字符串分配给多个变量,则运行时将从实习池中检索对文字字符串的相同引用,并将其分配给每个变量。
字符串文字由.NET运行时自动实现。 这意味着对具有相同值的字符串文字共享相同的字符串实例。 这样做是为了减少内存使用并提高性能。 这是一个安全的优化,因为字符串是不可变的。
您的代码编译为类似于以下内容的CIL指令:
IL_0001: ldstr "Hello world!" IL_0006: stloc.0 IL_0007: ldstr "Bonjour le monde" IL_000c: stloc.1 etc...
从ECMA规范中的ldstr
(“加载文字字符串”)指令的文档:
默认情况下,CLI保证两个ldstr指令的结果引用具有相同字符序列的两个元数据标记,返回完全相同的字符串对象(称为“字符串实习”的过程)。 可以使用
System.Runtime.CompilerServices.CompilationRelaxationsAttribute
和System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning
来控制此行为。
您还可以通过调用方法String.Intern来实习自己。
字符串文字大多数时候都是同一个对象,因为它们是常量和不可变的。
摘自microsoft docs :
每个字符串文字不一定会产生新的字符串实例。 当两个或多个根据字符串相等运算符(第7.9.7节)等效的字符串文字出现在同一个程序集中时,这些字符串文字引用相同的字符串实例。 例如,产生的输出
class Test { static void Main() { object a = "hello"; object b = "hello"; System.Console.WriteLine(a == b); } }
是True,因为两个文字引用相同的字符串实例。
.NET维护一个字符串池,因为它们是不可变的。 你不必关心它,因为它自己需要重用它们。