我有一个字符串,我想以某种方式修改.例如:将其反转或将其翻转.
我发现最快的方法是使用不安全的块和指针.
例如:
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)
)实际上返回对原始字符串的引用.如果现在修改了,那么所有其他引用也将如此.
最好使用a StringBuilder
来修改字符串,因为这是默认方式.
这样说吧:如果另一个程序员在执行时决定用代码中的1替换0,你会有什么感觉?你会用你所有的假设来玩它.字符串也是如此.每个人都希望它们是不可变的,并考虑到这一假设.如果你违反了,你很可能会引入错误-他们会真的很难追查.