我遇到了 “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”?我理解这个程序如下:
string.Intern(s)
实际上什么也没做,因为CLR保留了“Hello”字符串 - 它只返回保留的“Hello”字符串的地址(对象s具有相同的地址)据我了解实习池,它就像某种字符串字符串。或许我错过了什么?
答案 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);
没有用,因为它已经在编译阶段实习。