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

时间:2008-10-23 11:12:58

标签: c# .net

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

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

例如:

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

我有什么理由不这样做吗?

5 个答案:

答案 0 :(得分:16)

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

String interning是这个要求的一个很好的例子。为了加快一些字符串比较(并减少内存消耗),.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  

答案 1 :(得分:14)

  

我有什么理由不这样做吗?

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:1)

哦亲爱的主啊。

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

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

3)因为这是过早优化而且是E V I L。

答案 4 :(得分:0)

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