不仅字符串是不可变的,而且虽然string
是引用类型,但引用本身不是。也就是说,您传递的是string
按引用,但引用本身是按值传递的。
因此,对于引用类型,您可以修改参数所引用的对象(只要它是可修改的),但您不能修改参数所引用的内容,除非您通过引用传递它。
因此,当您尝试更改string
变量所指的内容时:
str = tmpStr;
它改变了str
本地引用的内容,但不影响原始参数所localString
引用的内容。
这样想,假设参数localString
引用位置 1000 的对象:
localString
+---------------+ 1000
| 1000 | -----------------> +---------------+
+---------------+ | Count: 1 |
| Value: "" |
+---------------+
然后当我们传递localString
给该方法时,它会创建引用的副本(as str
)并更新引用计数...
localString
+---------------+ 1000
| 1000 | -----------------> +---------------+
+---------------+ | Count: 2 |
| Value: "" |
str +---------------+
+---------------+ ^
| 1000 | ---------------------+
+---------------+
然后,当您将 str 分配给新字符串时,它会修改引用str
,但不会localString
:
localString
+---------------+ 1000
| 1000 | -----------------> +---------------+
+---------------+ | Count: 1 |
| Value: "" |
str +---------------+
+---------------+ 2500
| 2500 | ---------------------> +---------------+
+---------------+ | Count: 1 |
| Value: ... |
+---------------+
所以你的修改str
只改变了str
引用的内容,而不是原始的引用localString
,如果你想改变那个,那么你通过引用传递,这意味着这str
是对原始参数的引用(很像 ptr 到 ptr):
localString
+---------------+ 1000
| 2500 | ------------------> +---------------+
+---------------+ | Count: 2 |
^ | Value: "" |
str | +---------------+
+---------------+
| |
+---------------+
现在,当您更改str
它时,它也会更改参考localString
:
localString
+---------------+ 1000
| 1000 | -----+ +---------------+
+---------------+ | | Count: 0 |
^ | | Value: "" |
str | | +---------------+
+---------------+ | 2500
| | +----------------> +---------------+
+---------------+ | Count: 1 |
| Value: ... |
+---------------+
然后,当然,原始字符串(假设在这个例子中没有其他引用它)可以被垃圾收集......
所以,如果你真的想修改string
参数,通过ref
or传递它out
,或者你可以返回新的变异版本,或者存储在实例成员中(尽管传递实例成员是更高阶的耦合,可能会导致其他问题...)。