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”? 我理解这个程序如下:
- CLR在实习生池中保留“hello”(我将实习生池形象为一组string)。
-
string.Intern(s)
实际上什么都不做,因为CLR保留了“Hello”string – 它只是返回保留的“Hello”string的地址(对象s具有相同的地址) - 该程序通过指针更改“Hello”string的内容
- ??? 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);
没有用,因为它已经在编译阶段实现了。