为什么一些相同的字符串没有在.NET中实现?

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相同的参考?

对于不是字符串文字的string对象,对于ReferenceEquals调用应该为false

本质上,最后一行按巧合打印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 Method(String) 。 但是,我强烈建议您不要使用此方法,除非您有充分的理由这样做:它具有性能考虑因素和可能不需要的副作用(例如,已被实习的字符串无法进行垃圾回收)。

从msdn文档中的object.ReferenceEquals 这里 :

比较字符串时。如果objA和objB是字符串,则如果字符串是interned,则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)+""; 

在function上等同于:

 string s6 = s1;