C# 为什么有些相同的字符串不在.NET中驻留?

C# 为什么有些相同的字符串不在.NET中驻留?,c#,.net,string,C#,.net,String,字符串s5和s6具有与s1相同的值(“测试”)。基于字符串插入概念,这两条语句的计算结果都必须为true。有人能解释一下为什么s5没有与s1相同的引用吗?如果请求的子字符串恰好是原始字符串,那么子字符串方法足够聪明,可以返回原始字符串。链接到@DanielA.White评论中的参考源。因此s1。当s1长度为4时,子字符串(0,4)返回s1。显然,+操作符也有类似的优化 string s1 = "test"; string s5 = s1.Substring(0, 3)+"t"; string

字符串s5和s6具有与s1相同的值(“测试”)。基于字符串插入概念,这两条语句的计算结果都必须为true。有人能解释一下为什么s5没有与s1相同的引用吗?

如果请求的子字符串恰好是原始字符串,那么
子字符串
方法足够聪明,可以返回原始字符串。链接到@DanielA.White评论中的参考源。因此
s1。当
s1
长度为4时,子字符串(0,4)
返回
s1
。显然,+操作符也有类似的优化

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
在功能上等同于:

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

对于非字符串文本的
string
对象上的
ReferenceEquals
调用,应该得到
false

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

string s6 = s1;
上面的照片

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)
);

可以在.NET中插入字符串。这里没有说两个相同的字符串应该是同一个字符串实例。通常,编译器将插入相同的字符串文本,但并非所有字符串都是如此,当然也不是在运行时动态创建的字符串。

CLR不会插入所有字符串。默认情况下,所有
string
literals都会被插入。然而,以下是:

True True True
返回
true
,因为此处的行:

Console.WriteLine("{0} ", object.ReferenceEquals(s1, s6)); //True
有效地优化以返回相同的引用。它碰巧(可能)被拘留了,但这是巧合。如果要查看字符串是否已被插入,应使用


如果要在运行时插入字符串,可以使用
String.intern
并存储引用,请参见此处的MSDN文档:。但是,我强烈建议您不要使用此方法,除非您有充分的理由这样做:它有性能方面的考虑因素和潜在的不必要的副作用(例如,已插入的字符串不能被垃圾收集)。

来自object.ReferenceEquals的msdn文档:

比较字符串时。如果objA和objB是字符串,则如果字符串被插入,ReferenceEquals方法将返回true。它不执行值相等测试。在以下示例中,s1和s2相等,因为它们是单个插入字符串的两个实例。但是,s3和s4不相等,因为尽管它们具有相同的字符串值,但该字符串并没有被占用

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

编译器和库可能比您想象的要聪明。更好的问题是为什么
s6
会这样做。这不是“ReferenceEquals处理字符串时出错”的重复@dasblinkenlight您说得对,我的困惑源于最后两行产生不同输出的事实。两个结果都必须为真,或者两个结果都应为假。无论是哪种方式,我都在寻找不同输出的解释
当您传递一个空字符串进行字符串连接时,库优化会识别出这一点,并返回原始字符串
——显然,
。子字符串(0,4)
也会识别出请求的整个字符串,并且也会原封不动地返回它。
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