为什么字符串的索引器是只读的
本文关键字:只读 索引 字符串 为什么 | 更新日期: 2023-09-27 17:58:42
当我尝试用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对象的第一个元素。
CCD_ 11返回一个字符数组,比如c[N]。有了这个,您可以访问位于第0位的元素。
使用s = "pqr";
可以更改对象s所指向的字符串值。
这个答案不是为了解释readonly
问题,而是如果您想根据索引修改char
。
var s = "bcc".ToCharArray();
s[0] = 'a';
Console.WriteLine(s[0].ToString());