C#中损坏的string

我碰到“CorruptedString”(解决scheme) 。 以下是本书的程序代码:

var s = "Hello"; string.Intern(s); unsafe { fixed (char* c = s) for (int i = 0; i < s.Length; i++) c[i] = 'a'; } Console.WriteLine("Hello"); // Displays: "aaaaa" 

为什么这个程序显示“aaaaa”? 我理解这个程序如下:

  1. CLR在实习生池中保留“hello”(我将实习生池形象为一组string)。
  2. string.Intern(s)实际上什么都不做,因为CLR保留了“Hello”string – 它只是返回保留的“Hello”string的地址(对象s具有相同的地址)
  3. 该程序通过指针更改“Hello”string的内容
  4. ??? Hellostring应该在实习生池中不存在,应该是错误的! 但是没关系; 该程序运行成功。

据我了解实习生池,它就像某种string的字典串。 或者我错过了什么?

当你第一次使用“Hello”的时候,它会被join到应用程序的全局string存储中。 根据你在unsafe模式下执行的事实(更多关于这里的 unsafe ),你可以直接引用存储在最初分配给strings值的位置的数据,所以通过

 for (int i = 0; i < s.Length; i++) c[i] = 'a'; 

你正在编辑内存中的内容。 当它下次访问internedstring的时候,它会在内存中使用相同的地址,保存你刚才改变的数据。 没有unsafe这是不可能的。 string.Intern(s); 在这里不起作用; 如果你注释掉它,它的行为是一样的。

然后通过

 Console.WriteLine("Hello"); // Displays: "aaaaa" 

.NET查看是否有一个地址为"Hello"获得的地址,并且有:您刚更新为"aaaaa"'a'字符的数量由"Hello"的长度决定。

即使@Jaroslav Kadlec答案是正确和完整的我想添加一些关于代码的行为,为什么string.Intern(s);更多信息string.Intern(s);这种情况下是无用的。

关于实习生池

实际上,.NET会自动执行string的所有stringinterning,这是通过使用一个特殊的表来存储对应用程序中所有唯一string的引用。

但是,重要的是要注意,只有显式声明的string在编译阶段被执行

考虑下面的代码:

 var first = "Hello"; //Will be interned var second = "World"; //Will be interned var third = first + second; //Will not be interned 

当然,在某些情况下,我们希望在运行时实习一些string,这可以通过String.Intern进行检查后通过String.Intern来完成。

所以回到OP的片段:

 //... var s = "Hello"; string.Intern(s); //... 

在这种情况下string.Intern(s); 没有用,因为它已经在编译阶段实现了。