为什么字符串的索引器是只读的

本文关键字:只读 索引 字符串 为什么 | 更新日期: 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());