当我尝试分配给字符串中的单个字符时,s[i] = c
出现编译器错误:
string s = "bcc";
s[0] = 'a'; // shows compile time error - indexer cannot be assigned - it's readonly
但是,这有效:
s.ToCharArray()[0] = 'a';
我们还可以将字符串完全分配给acc
:
s = "acc"
这:
s="acc"
...正在更改变量的值以引用不同的字符串。如果允许:
s[0] = 'a';
这不会改变变量的值——它必须改变所s
引用的字符串的内容。字符串在 .NET 中是不可变的,因此这是不允许的。
区分更改变量的值和更改它所引用的对象中的数据很重要。
更改的内容s.ToCharArray()
不会对字符串s
或字符串做任何事情 - 它只会改变新创建的数组,该数组是字符串中数据的副本。
来自MSDN:
字符串是不可变的——字符串对象的内容在创建对象后不能更改,尽管语法使它看起来好像您可以这样做。例如,当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给 b。然后字符串“h”就可以进行垃圾回收了。
s.ToCharArray()
正在将字符串的内容复制到数组中。但是你不能修改这个字符串引用中的第一个字符——这个字符串本身永远不会改变。
字符串在 .NET 中实现为写时复制(更准确地说:基于字符串池)和引用类型。您要做的是获取构成字符串的基础 char[] 并更改它。但是,由于string
它是作为写时复制实现的,因此如果成功,您不仅会更改一个字符串,还会更改所有字符串。
例如,如果您的代码更改字符串会发生这种情况:(以说明不正确的假设):
string s = "foo"; // create instance with foo
string t = s; // copy reference, contents aren't changed
char[] ch = s.ToCharArray(); // attempt to access underlying contents
ch[0] = 'b'; // attempts to change the underlying contents
Console.WriteLine(t); // 'boo'?
当你尝试它时,t 将是 'foo',因为底层内容保持不变。ToCharArray 复制底层内容,从而保护底层内容,以便对同一字符串对象的其他引用不受影响。
这也是这样的代码是一种不好的做法的原因:
string s = "";
for (int i=0; i<10000; ++i)
{
// makes a new instance of the string, copies the contents
// and appends a single char... as you can see 10K times...
s = s + "a";
}
这就是字符串被实现为不可变的原因:保护对字符串的引用不被获取不同的内容。
另请参阅此处以了解字符串池的行为。
不能s[0]
直接比较s.ToCharArray()[0]
。
随着s[0]
您尝试访问 String 对象的第一个元素。
s.ToCharArray()
返回一个字符数组,例如 c[N]。有了这个,您可以访问第 0 个定位元素。
并且随着s = "pqr";
您更改对象 s 指向的字符串值。
这个答案不是为了解释这个readonly
问题,而是如果你想修改char
索引的基础。
var s = "bcc".ToCharArray();
s[0] = 'a';
Console.WriteLine(s[0].ToString());