C#中的字符串已损坏

时间:2016-12-19 10:00:56

标签: c# string

我遇到了 “CorruptedString” (Solution) 。以下是本书中的以下程序代码:

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”(我将实习池视为一组字符串)。
  2. string.Intern(s)实际上什么也没做,因为CLR保留了“Hello”字符串 - 它只返回保留的“Hello”字符串的地址(对象s具有相同的地址)
  3. 程序通过指针
  4. 更改“Hello”字符串的内容
  5. ???实习生池中应该没有Hello字符串,应该是错误的!但没关系;该程序运行成功。
  6. 据我了解实习池,它就像某种字符串字符串。或许我错过了什么?

2 个答案:

答案 0 :(得分:65)

当你使用&#34; Hello&#34;这是第一次,它被嵌入到应用程序全局字符串存储中。 根据您在unsafe模式下执行的事实(更多关于unsafe here),您可以直接引用存储在最初为string {值分配的位置中的数据{1}},所以

s

你正在编辑内存中的内容。当它下次访问实习字符串的存储时,它将在内存中使用相同的地址,保存您刚刚更改的数据。没有for (int i = 0; i < s.Length; i++) c[i] = 'a'; ,这是不可能的。 unsafe在这里没有发挥作用;如果你发表评论,它的行为是一样的。

然后通过

string.Intern(s);

Console.WriteLine("Hello"); // Displays: "aaaaa" 查看是否有.NET获取的地址条目,并且:您刚刚更新为"Hello"的地址。 "aaaaa"个字符的数量由'a'的长度确定。

答案 1 :(得分:5)

尽管@Jaroslav Kadlec答案是正确且完整的,但我想补充一些有关代码行为的更多信息,以及为什么string.Intern(s);这种情况下无效。< / p>

关于实习生池

实际上.NET会自动为所有字符串文字执行字符串实习,这是通过使用一个特殊的表来完成的,该表存储对应用程序中所有唯一字符串的引用。

然而,重要的是要注意在编译阶段只显式声明字符串

请考虑以下代码:

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

当然,在某些情况下,我们希望在运行时实习一些字符串,这可以在String.Intern核对后由String.IsInterned完成。

回到OP的片段:

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

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