Почему изменение этой строки также изменяет содержимое другой отдельной строки? - PullRequest
1 голос
/ 06 августа 2020

В моей функции stati c main у меня есть следующий код:

string str1 = "aaaaaaaaa";
pointerTest();
Console.WriteLine( "str1 is: " + str1 );

stati c pointerTest -метод, который объявлен как unsafe, содержит следующее :

string str2 = "aaaaaaaaa";
fixed( char* ptr = str2 )
{
    for( int i = 0; i < str2.Length / 3; ++i )
        ptr[i] = 'z';
}

Console.WriteLine( "str2 is: " + str2 );

Обратите внимание, как str1 и str2 объявлены независимо, но имеют одинаковое содержимое.

Ожидаемый результат этой программы: :

str2 is: zzzaaaaaa
str1 is: aaaaaaaaa

Когда я запускаю программу, фактический вывод показывает это:

str2 is: zzzaaaaaa
str1 is: zzzaaaaaa

Когда я меняю str2 или str1 на не имеют точно такого же содержания (например, добавив еще одну букву «а» в конце str2), программа действует как ожидалось. Если обнаружил, что такое поведение существует как в . Net Core 3.1 , так и Mono (не уверен в точной версии, я использовал Repl.It )

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

1 Ответ

2 голосов
/ 06 августа 2020

Моя теория состоит в том, что это происходит из-за оптимизации компилятора , в частности процесса, называемого интернирования строки :

Компилятор признает, что не нужно выделять str2 сам по себе, поскольку в памяти уже есть точно такая же последовательность символов , выделенная с инициализацией str1. Таким образом, вместо того, чтобы выделять его заново, он делает str2 ссылку на место, на которое str1 уже указывает. Подробнее об этом можно прочитать здесь .

Строки считаются неизменяемыми в C#, поэтому - при нормальных обстоятельствах - не должно быть возможности изменить их содержимое в любом виде, форме или форме.

Поскольку этот код использует ключевое слово unsafe и указатель-логи c, не гарантируется, что он не вызовет неопределенное поведение , что приводит к к неожиданному результату.

Единственный способ обойти эту «проблему» - это придерживаться спецификаций C# и рассматривать Strings как неизменяемые.

...