这可能是在其他地方被问过的,但是当我做一个简单的搜索时我只是没有看到它。我正在使用C#类进行工作,我知道字符串是不可变的,并且可以通过代码更改stringBuilder。
但是为什么C#允许你更改字符串,如果它是不可变的?
或者它是否允许您更改字符串,因为它需要一个新的内存点并创建另一个孔字符串变量并放弃其他变量地址位置。如果是这种情况并且自动垃圾收集通过并整理C#内存位置,那么一个人是否使用string或stringBuilder真的很重要吗?
代码:
string sss = 'abcd';
sss = 'ghy';
sss = 'nnnnnn';
答案 0 :(得分:4)
通过将变量赋值给不同的值来改变变量的值。
这不会改变变量所引用的值。
答案 1 :(得分:2)
你基本上已经回答了这个问题。简短的回答是“C#做不让你改变字符串”
出于各种设计原因,c#中的“String”实现为reference-type。你正在做的是改变sss引用 - 你没有改变被引用的东西。 'abcd'与'ghy'分开存在与'nnnnn'分开存在你没有将一件事变成另一件事。你正在创造一个全新的东西,然后改变哪一个sss引用。
字符串在C#中是不可变的,以使它们表现,如value-types,即使它们已实现为reference types。为什么?因为替代方案更糟糕:
考虑一个示例,其中字符串是引用类型,但不是不可变的 - 您可以将'abcd'更改为'ab12'。那怎么样?
string mutableString = "abcd";
string anotherRef = mutableString;
mutableString.mutateTo("ab12"); //A method that doesn't exist - for exposition only
此时,另一个也将是“ab12” - 这似乎非常不直观。
StringBuilder更多是在特殊情况下使用的表演事物。对于大多数字符串连接,没关系。如果你有两个字符串,如“我的名字是”和“皮特”,你连接它们 - 那么你最终会得到一个新的字符串“我的名字是皮特”,旧的字符串可能会被困在内存的某个地方。没有大碍。你有你想要的完整字符串 - 没有浪费很多时间或内存。但是考虑一个更极端的情况:如果你有更多的话会怎么样:“快速”“棕色”“狐狸”“跳”“超过”“懒惰”“狗”你想要将它们连接在一起:
你可以看到这个方法产生了许多你并不真正关心的额外中间字符串,但它们都会被分配 - 这需要时间 - 而且它们都会在内存中挂起,直到GC摆脱他们。 StringBuilder为您提供了一种连接方法,而无需分配每个中间结果。
注意 - 下一部分不是严格正确的,但它足够接近这个例子。 StringBuilder的内部实现没有合约行为:您可以将其视为“Lazy concatenation”。它可以在内部保存对所有组件字符串的引用,但是在完成附加字符串后调用ToString
方法之前,不会为最终结果重新分配空间。这使得它可以计算出它需要的最终大小,并为整个组合字符串重新分配足够的空间 - 一次而不是 n 次。