为什么我永远不会使用不安全的块来修改字符串?

我有一个字符串,我想以某种方式修改。 例如:反转它或将其翻转。

我发现最快的方法是使用不安全的块和指针。

例如:

unsafe { fixed (char* str = text) { *str = 'X'; } } 

有什么理由我永远不应该这样做吗?

.Net框架要求字符串是不可变的。 由于这一要求,它能够优化各种操作。

字符串实习是这个要求被大量使用的一个很好的例子。 为了加快一些字符串比较(并减少内存消耗),.Net框架维护一个指针字典,所有预定义的字符串都将存在于这个字典或你调用String.intern方法的任何字符串中。 当调用IL指令ldstr时,如果我们已经分配了字符串,它将检查实习字典并避免内存分配,注意: String.Concat不会检查实际字符串。

.net框架的这个属性意味着如果你开始直接使用字符串,你可以破坏你的实习表,反过来破坏对同一个字符串的其他引用。

例如:

  // these strings get interned string hello = "hello"; string hello2 = "hello"; string helloworld, helloworld2; helloworld = hello; helloworld += " world"; helloworld2 = hello; helloworld2 += " world"; unsafe { // very bad, this changes an interned string which affects // all app domains. fixed (char* str = hello2) { *str = 'X'; } fixed (char* str = helloworld2) { *str = 'X'; } } Console.WriteLine("hello = {0} , hello2 = {1}", hello, hello2); // output: hello = Xello , hello2 = Xello Console.WriteLine("helloworld = {0} , helloworld2 = {1}", helloworld, helloworld2); // output : helloworld = hello world , helloworld2 = Xello world 

有什么理由我永远不应该这样做吗?

是的,非常简单:因为.NET依赖于字符串是不可变的这一事实。 某些操作(例如s.SubString(0, s.Length) )实际上返回对原始字符串的引用。 如果现在修改了,那么所有其他引用也将如此。

最好使用StringBuilder来修改字符串,因为这是默认方式。

这样说吧:如果另一个程序员在执行时决定用代码中的1替换0,你会有什么感觉? 你会用你所有的假设来玩它。 字符串也是如此。 每个人都希望它们是不可变的,并考虑到这一假设。 如果你违反了这一点,你很可能会引入错误 – 而且它们很难被追踪。

亲爱的主啊,是的。

1)因为该课程不是为了被篡改而设计的。

2)因为字符串在整个框架中被设计和预期是不可变的。 这意味着其他人编写的代码(包括MSFT)期望字符串的基础值永远不会改变。

3)因为这是过早优化而且是EVI L.

同意StringBuilder,或者只是将你的字符串转换为字符/字节数组并在那里工作。 另外,你给出了“upcasing”的例子 – String类有一个ToUpper方法,如果这个方法至少和你不安全的“upcasing”一样快,我会吃掉我的帽子。