2013-02-12 5 views
2

При попытке присвоить отдельные символы в строке с 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" 
+3

Строки неизменяемы в .NET. Массивов обычно нет. – leppie

+2

«это работает», только в том случае, если отсутствует компилятор или ошибка времени выполнения. Значение 's' не изменяется. –

+0

Справа, отмечено :) – Igoy

ответ

3

Это:

s="acc" 

... изменяет значение переменной для ссылки на другую строку. Если бы это было разрешено:

s[0] = 'a'; 

, что не будет изменение значения переменного - он должен изменить содержимое строки, s ссылки. Строки неизменяемы в .NET, поэтому это недопустимо.

Важно различать изменение значения переменной и изменение данных в объекте, к которому он относится.

Изменение содержимого s.ToCharArray() не делает ничего, либо sили строки - это просто мутирует вновь созданный массив, который является копию данных в строке.

0

Вы не можете сравнить s[0] напрямую с s.ToCharArray()[0].

С помощью s[0] вы пытаетесь получить доступ к первому элементу объекта String.

s.ToCharArray() возвращает массив символов c [N]. При этом вы можете получить доступ к 0-му позиционируемому элементу.

И с s = "pqr"; вы меняете строковое значение, на которое указывает объект s.

0

Строка в .NET реализована как copy-on-write (точнее: на основе пула строк) и как ссылочный тип. То, что вы пытаетесь сделать, это получить основной символ [], который составляет строку и изменить ее. Однако, поскольку string реализован как copy-on-write, если это было успешным, вы бы не просто изменили одну строку, а все из них.

Например, это то, что может произойти, если ваш код будет изменить строку: (чтобы проиллюстрировать неверное предположение):

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'? 

При попытке его, т будет «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 о поведении пула строк.

+0

Любые объяснения для downvote? – atlaste

+0

Кажется, я не могу объяснить, что я имею в виду. В соответствии с тем, что я могу читать в рефлекторе, это «copy-on-write» (ну, с помощью stringpool, который есть), что означает, что изменение ch [0] 'приведет к повреждению всех ссылок - что будет катастрофой. Я пытаюсь объяснить, что произойдет, если его код изменит строку, я знаю, что она не меняет «foo» на «boo» ... позвольте мне посмотреть, могу ли я изменить свой ответ – atlaste

+0

@leppie здесь, извините за то, что я не являюсь носителем английского языка ... Надеюсь, это касается того, что я пытался сделать лучше? – atlaste

3

От MSDN:

Strings are immutable--the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to b. The string "h" is then eligible for garbage collection.

s.ToCharArray() копирует содержимое строки в массив. Но вы не можете изменить первый символ в этой строковой ссылке - эта строка сама по себе никогда не изменится.

0

Этот ответ не объясняет проблему readonly, но если вы хотите изменить базу на индекс.

 var s = "bcc".ToCharArray(); 
     s[0] = 'a'; 
     Console.WriteLine(s[0].ToString()); 
Смежные вопросы