В чём может быть опасность изменения строк? (Пример кода)
Сделал пример кода, меняющего содержимого строки в памяти.
void Main()
{
GC.Collect();
string s1 = "abcdef";
string s2 = null;
s2 = "abc";
s2 += "def";
string s3 = "abcdef";
$"s1: {s1}".Dump();
$"s2: {s2}".Dump();
$"s3: {s3}".Dump();
GC.Collect();
//
"".Dump();
HackedString str1 = new() { STRING = s1 };
HackedString str2 = new() { STRING = s2 };
HackedString str3 = new() { STRING = s3 };
//
str3.SetChar(0, 'A');
str3.SetChar(5, 'U');
$"s1: {s1}".Dump();
$"s2: {s2}".Dump();
$"s3: {s3}".Dump();
}
unsafe ref struct HackedString
{
public string STRING { get; set; }
private void* _pointer(string _string) => (void*)*(nint*)(nint)(&_string);
public char GetChar(nint char_position)
{
void* p = _pointer(STRING);
long offset = 4 + char_position;
char* ch = (char*)p + offset;
return *ch;
}
public void SetChar(nint char_position, char new_char)
{
void* p = _pointer(STRING);
long offset = 4 + char_position;
char* ch = (char*)p + offset;
*ch = new_char;
}
public override string ToString() => STRING;
}
Вывод:
s1: abcdef
s2: abcdef
s3: abcdef
s1: AbcdeU
s2: abcdef
s3: AbcdeU
Как видно, строки s1 и s2 имеют одно и то же содержимое. Начитавшись "умных" статей, в которых писалось, что строки экономят память, и если содержимое совпадает - то под капотом одна и та же ссылка. Но по экспериментам это оказалось не так. Даже запрос к сборщику мусора (с надеждой что он найдёт дубликат) не дал эффекта. Изначально записанные строки s1 и s3 содержать под капотом одну и ту же ссылку на char[], но строка s2, которая только потом стала походить на s1 и s3 имеет другой char[], хоть и с идентичным содержимым.
Выходит, что экономия происходит только на этапе компиляции?
И уже созданные после запуска программы строки можно менять без опасения?
Источник: Stack Overflow на русском