理解 C# 中的字符串不变性
介绍
在本指南中,我们将讨论字符串和字符串的不变性。我们将使用 C# 编程语言来解释字符串并给出示例。如果您难以理解字符串的概念,或者想要重新认识字符串和不变性,那么本指南适合您。
读完本指南后,您将了解:
什么是字符串以及不可变的含义
为什么字符串是不可变的
字符串不变性的优缺点
字符串和不变性
在编程世界中,字符串是 System.Char 字符的数组,这些字符组合在一起表示文本。在 C# 编程语言中,您可以声明一个字符串并打印出其值,如下所示:
string str = "Hello World";
Console.WriteLine(str);
//This will print out "Hello World" to the console.
当你创建一个字符串时,它是不可变的。这意味着它是只读的。当某些东西是不可变的或只读的,这意味着它以后不能被改变。
为什么字符串是不可变的
在 C# 中,CLR(公共语言运行时)负责确定将字符串存储在何处。在上一节中,我指出字符串是字符数组。CLR 实现数组来存储字符串。数组是固定大小的数据结构,这意味着它们的大小不能动态增加或减少。一旦为数组分配了大小,就无法更改大小。要使数组变大,必须将数据复制并克隆到新数组中,然后由 CLR 将其放入新的内存块中。如果您编辑字符串,则实际上并没有修改该字符串;相反,CLR 正在为修改后的字符串创建新的内存引用,并且原始字符串将通过垃圾回收从内存中删除。
让我们看看内部情况
虽然这不是必须的,但绝对有必要了解在编写代码时内存中发生了什么,无论是字符串、数据结构还是其他内容。它以多种方式提供帮助,无论是修复软件错误还是诊断内存泄漏或性能问题。我发现最好的比较是了解汽车引擎盖下发生了什么。虽然了解汽车引擎盖下的部件以及它们在汽车出现问题时的作用,但了解它们会很有帮助。
让我们仔细看看上一节中的例子。我们将创建一个新的字符串,然后修改它,并解释在这整个过程中内存中发生了什么。
string str = "Hello World";
Console.WriteLine(str);
//This will print out "Hello World" to the console.
在程序中,我们创建一个名为str的字符串对象,并为其赋值“Hello World”。然而,在内存中,CLR 正在创建空间块来存储此变量。为简单起见,我们假设 CLR 使用内存位置 1000 来存储str。由于这是一个对象,CLR 会将其存储在堆上,而不是堆栈上。现在,让我们修改这个字符串。
str += " edited";
Console.WriteLine(str);
//This will print out "Hello World edited" to the console.
运行此代码时,您将看到“Hello World edited”。由于此字符串是不可变的,CLR 会再次在内存中创建新的空间块来存储此变量。CLR 将为这个新变量分配一个新的内存位置,比如说位置 1500。最终,垃圾收集器将处理存储在位置 1000 中的原始字符串并将其从内存中清除。
优点和缺点
与几乎所有其他事物一样,有使用不可变字符串的理由,也有不使用不可变字符串的理由。为什么要使用不可变字符串?一个优点是它们是线程安全的。如果您使用的是多线程系统,则不会有死锁或任何并发问题的风险,因为当您修改字符串时,您实际上只是在内存中创建一个新对象。另一个优点是您不必担心意外更改它们。您不需要采取可变对象可能需要采取的额外安全措施(即防御性对象复制)。
为什么不可变的字符串是个坏主意?主要问题是不断更改字符串会导致性能问题。我们将在代码块中解释这一点。如果您参考上一节的代码片段,您将看到我们只修改了一次字符串。假设我们有这样的场景:
string str = "Hello World";
Console.WriteLine(str);
//This will print out "Hello World" to the console.
for (int i = 0; i < 10; i++)
{
str += " again";
Console.WriteLine(str);
}
您可以在下面看到输出。此代码在原始“Hello World”之后的每次迭代(十次)中都会打印“again”。但是,对于每次迭代,由于字符串是不可变的,因此在内存中发生的事情是 CLR 十次在内存中分配新空间并存储新的 str 变量,并且每次它都会创建更大的块来保存更多数据。
如果我们这样做了一千次、一万次或一百万次会怎么样?这将需要 CLR 分配大量内存,垃圾收集器需要完成大量工作。在所有这些情况下,您很可能会看到性能下降。如果您发现自己处于这样的情况,可变对象可能就是您所需要的。一个建议是 StringBuilder 对象。
结论
本指南介绍了字符串默认不可变的原因以及它们在内存中的处理方式。我们查看了创建和修改字符串的示例,并解释了每个步骤中内存中发生的事情。然后,我们讨论了字符串的不可变性为什么是一件好事,也可能是一件坏事,以及如果您发现自己需要的话,有哪些替代方案。字符串是软件世界中非常重要的概念,在大多数技术工作面试中,您应该会收到与字符串相关的问题。
可能需要了解的面试问题:
- 我们应该使用可变还是不可变的字符串?
- 默认情况下字符串是可变的还是不可变的?
- 为什么字符串是不可变的?
我希望你喜欢阅读本指南,并希望它能帮助你理解计算机科学领域最重要的概念之一!如果你有兴趣阅读我的其他作品,请查看按值与按引用:函数的返回值。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~