Ответ
Строки в C# — это неизменяемые (immutable) последовательности символов Unicode, представленные типом System.String. Их ключевые особенности:
1. Неизменяемость (Immutability) При любой модификации создаётся новый объект строки. Это обеспечивает потокобезопасность и безопасность, но требует аккуратной работы с производительностью.
string original = "Hello";
string modified = original + " World"; // Создаётся новая строка, "Hello" остаётся в памяти
Console.WriteLine(object.ReferenceEquals(original, modified)); // False
2. Интернирование строк (String Interning) CLR хранит литералы в пуле строк (intern pool), что позволяет повторно использовать одинаковые строковые литералы для экономии памяти.
string a = "test";
string b = "test";
string c = new StringBuilder().Append("te").Append("st").ToString();
Console.WriteLine(object.ReferenceEquals(a, b)); // True (интернирование)
Console.WriteLine(object.ReferenceEquals(a, c)); // False (не интернирована)
Console.WriteLine(string.IsInterned(c) != null); // Можно принудительно интернировать
3. Оптимизация конкатенации
Для множественных операций конкатенации всегда используйте StringBuilder вместо оператора + или string.Concat() в цикле.
// Плохо: создаёт промежуточные строки O(n²)
string result = "";
for (int i = 0; i < 100; i++) result += i;
// Хорошо: эффективное построение
var sb = new StringBuilder();
for (int i = 0; i < 100; i++) sb.Append(i);
string result = sb.ToString();
4. Форматирование
Используйте интерполяцию строк ($"Value: {value}") вместо string.Format() для лучшей читаемости и производительности (компилятор оптимизирует в string.Format).
5. Юникод и суррогатные пары
Один символ (char) может занимать 2 байта (UTF-16), а для символов за пределами Basic Multilingual Plane (например, эмодзи) требуется суррогатная пара — два char.
string emoji = "😀";
Console.WriteLine(emoji.Length); // 2 (суррогатная пара)
Console.WriteLine(new StringInfo(emoji).LengthInTextElements); // 1 (графема)
6. Сравнение строк
Используйте StringComparison для явного указания правил сравнения, особенно в культурно-зависимых сценариях.
bool equal = string.Equals("test", "TEST", StringComparison.OrdinalIgnoreCase);
Практическое правило: При активной работе со строками (парсинг, построение) всегда оценивайте необходимость использования StringBuilder, ReadOnlySpan<char> (для .NET Core) или массивов символов.