为什么一些相同的字符串没有驻留在 .NET 中

本文关键字:NET 字符串 为什么 | 更新日期: 2023-09-27 18:29:48

string s1 = "test";
string s5 = s1.Substring(0, 3)+"t"; 
string s6 = s1.Substring(0,4)+"";   
Console.WriteLine("{0} ", object.ReferenceEquals(s1, s5)); //False
Console.WriteLine("{0} ", object.ReferenceEquals(s1, s6)); //True

字符串 s5 和 s6 的值与 s1 相同("test"(。基于字符串实习概念,两个语句的计算结果都必须为 true。有人可以解释为什么 s5 没有与 s1 相同的参考吗?

为什么一些相同的字符串没有驻留在 .NET 中

您应该false对非字符串文本的string对象进行ReferenceEquals调用。

本质上,最后一行打印True巧合:发生的情况是,当您传递一个空字符串进行字符串连接时,库优化会识别这一点,并返回原始字符串。这与实习无关,因为从控制台读取或以任何其他方式构造的字符串也会发生同样的事情:

var s1 = Console.ReadLine();
var s2 = s1+"";
var s3 = ""+s1;
Console.WriteLine(
    "{0} {1} {2}"
,   object.ReferenceEquals(s1, s2)
,   object.ReferenceEquals(s1, s3)
,   object.ReferenceEquals(s2, s3)
);

以上打印

True True True

演示。

CLR 不会实习所有字符串。默认情况下,所有string文本都处于驻留状态。但是,以下几点:

Console.WriteLine("{0} ", object.ReferenceEquals(s1, s6)); //True

返回true,因为此处的行:

string s6 = s1.Substring(0,4)+"";  

经过有效优化,可返回相同的引用。它碰巧(可能(被拘留,但这是巧合。如果你想查看一个字符串是否被暂留,你应该使用 String.IsInterned((

如果要在运行时实习字符串,可以使用String.Intern并存储引用,根据此处的 MSDN 文档:String.Intern 方法(字符串(。但是,我强烈建议您不要使用此方法,除非您有充分的理由这样做:它具有性能考虑和可能不需要的副作用(例如,无法对已暂留的字符串进行垃圾回收(。

来自对象的 msdn 文档。参考等于这里:

比较字符串时。如果 objA 和 objB 是字符串,则 ReferenceEquals 方法在字符串被暂留时返回 true。它不执行值相等性测试。在下面的示例中,s1 和 s2 相等,因为它们是单个暂留字符串的两个实例。但是,s3 和 s4 不相等,因为尽管它们具有相同的字符串值,但该字符串不会被保留。

using System;
public class Example
{
   public static void Main()
   {
      String s1 = "String1";
      String s2 = "String1";
      Console.WriteLine("s1 = s2: {0}", Object.ReferenceEquals(s1, s2));
      Console.WriteLine("{0} interned: {1}", s1, 
                        String.IsNullOrEmpty(String.IsInterned(s1)) ? "No" : "Yes");
      String suffix = "A";
      String s3 = "String" + suffix;
      String s4 = "String" + suffix;
      Console.WriteLine("s3 = s4: {0}", Object.ReferenceEquals(s3, s4));
      Console.WriteLine("{0} interned: {1}", s3, 
                        String.IsNullOrEmpty(String.IsInterned(s3)) ? "No" : "Yes");
   }
}
// The example displays the following output:
//       s1 = s2: True
//       String1 interned: Yes
//       s3 = s4: False
//       StringA interned: No

.NET 中的字符串可以暂留。任何地方都没有说 2 个相同的字符串应该是同一个字符串实例。通常,编译器将暂存相同的字符串文本,但并非所有字符串都是如此,在运行时动态创建的字符串当然也是如此。

Substring 方法足够聪明,可以在请求的子字符串完全是原始字符串的情况下返回原始字符串。 链接到@DanielA.White在评论中找到的参考来源。 因此,当s1长度为 4 时,s1.Substring(0,4)返回s1。 显然 + 运算符具有类似的优化,因此

string s6 = s1.Substring(0,4)+"";

在功能上等效于:

string s6 = s1;