为什么字符串索引器只读?

时间:2013-02-12 08:18:08

标签: c# .net string

当我尝试使用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"

5 个答案:

答案 0 :(得分:4)

此:

s="acc"

...正在更改变量的值以引用不同的字符串。如果允许的话:

s[0] = 'a';

不会改变变量的值 - 它必须改变s引用的字符串的内容。字符串在.NET中是不可变的,所以这是不允许的。

区分更改变量的值和更改其引用的对象内的数据非常重要。

更改s.ToCharArray()的内容对s 字符串没有任何作用 - 它只是改变了新创建的副本数组字符串中的数据。

答案 1 :(得分:3)

来自MSDN

  

字符串是不可变的 - 创建对象后无法更改字符串对象的内容,尽管语法使其看起来好像可以执行此操作。例如,当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给b。然后字符串“h”有资格进行垃圾收集。

s.ToCharArray()正在将字符串的内容复制到数组中。但是你不能修改这个字符串引用中的第一个字符 - 这个字符串本身永远不会改变。

答案 2 :(得分:2)

一个字符串在.NET中实现为copy-on-write(更确切地说:基于字符串池)和reference-type。你要做的是获取构成字符串的底层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"; 
}

这就是为什么字符串被实现为不可变的原因:保护对字符串的引用以获取不同的内容。

另请参阅here有关字符串池的行为。

答案 3 :(得分:0)

您无法直接将s[0]s.ToCharArray()[0]进行比较。

使用s[0],您正在尝试访问String对象的第一个元素。

s.ToCharArray()返回一个字符数组,表示c [N]。有了这个,您可以访问第0个定位元素。

使用s = "pqr";,您正在更改对象s所指向的字符串值。

答案 4 :(得分:0)

这个答案不是要解释readonly问题,而是要修改索引的char基础。

        var s = "bcc".ToCharArray();
        s[0] = 'a';
        Console.WriteLine(s[0].ToString());