C#中的字符串已损坏

LmT*_*oon 70 c# string

我遇到了"CorruptedString"(解决方案).以下是本书中的以下程序代码:

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"
Run Code Online (Sandbox Code Playgroud)

为什么这个节目会显示"aaaaa"?我理解这个程序如下:

  1. CLR中实习生池储备"你好"(我的图像实习生池作为一组字符串).
  2. string.Intern(s) 实际上什么也没做,因为CLR保留了"Hello"字符串 - 它只返回保留的"Hello"字符串的地址(对象s具有相同的地址)
  3. 该程序通过指针更改"Hello"字符串的内容
  4. ??? 实习生池中应该没有Hello字符串,应该是错误的!但没关系; 该程序运行成功.

据我了解实习池,它就像某种字符串字符串.或许我错过了什么?

Jar*_*lec 65

当您第一次使用"Hello"时,它会被插入到应用程序全局字符串存储中.基于您在unsafe模式下执行的事实(更多关于unsafe 此处),您可以直接引用存储在最初为字符串值分配的位置中的数据s,因此通过

for (int i = 0; i < s.Length; i++)
      c[i] = 'a';
Run Code Online (Sandbox Code Playgroud)

你正在编辑内存中的内容.当它下次访问实习字符串的存储时,它将在内存中使用相同的地址,保存刚才更改的数据.没有,这是不可能的unsafe.string.Intern(s);在这里没有发挥作用; 如果你评论它,它的行为是一样的.

然后

Console.WriteLine("Hello"); // Displays: "aaaaa"
Run Code Online (Sandbox Code Playgroud)

.NET查看是否有获取地址的条目,"Hello"并且:您刚刚更新的地址"aaaaa".'a'字符数由长度决定"Hello".

  • 实际上`string.Intern(s)`在这个程序中什么都不做.你可以评论这一行,程序将工作相同(因为"你好"保留).但我同意你的看法 (6认同)
  • 呵呵.JIT的儿子. (6认同)

Sid*_*Sid 5

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

关于实习生池

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

但是,重要的是要注意在编译阶段只有显式声明的字符串被实现.

请考虑以下代码:

var first = "Hello"; //Will be interned
var second = "World"; //Will be interned
var third = first + second; //Will not be interned
Run Code Online (Sandbox Code Playgroud)

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

所以回到OP的片段:

//...
var s = "Hello";
string.Intern(s);
//...
Run Code Online (Sandbox Code Playgroud)

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