Ответ
В C# тип string (System.String) является ссылочным типом (reference type). Он хранится в управляемой куче (heap), а переменная содержит ссылку на этот объект.
Почему возникает путаница? string обладает семантикой неизменяемости (immutable) и некоторыми особенностями сравнения, которые делают его поведение похожим на значимый тип (value type).
Ключевые характеристики string:
- Ссылочный тип: Размещается в куче, передача в методы происходит по ссылке.
- Неизменяемый (Immutable): Любая операция, которая якобы "изменяет" строку (
Trim(),Replace(),+=,ToUpper()), на самом деле создает и возвращает новый объект строки в памяти. - Может быть
null: Как и любой ссылочный тип. - Интернирование строк (String Interning): CLR хранит уникальные строковые литералы в специальном пуле во время компиляции и выполнения, чтобы экономить память. Это оптимизация, не меняющая природу типа.
- Переопределенный оператор
==: Дляstringоператор==сравнивает значения строк, а не ссылки (что и делает его похожим на значимый тип). Для сравнения ссылок нужно использоватьobject.ReferenceEquals().
Наглядный пример:
string a = "Hello"; // Создается строка в куче, 'a' ссылается на нее.
string b = a; // 'b' теперь ссылается на ТОТ ЖЕ объект, что и 'a'.
Console.WriteLine(object.ReferenceEquals(a, b)); // True (одинаковые ссылки)
b += " World!"; // Операция создает НОВУЮ строку "Hello World!".
// 'b' теперь ссылается на новый объект, 'a' — на старый.
Console.WriteLine(a); // "Hello"
Console.WriteLine(b); // "Hello World!"
Console.WriteLine(object.ReferenceEquals(a, b)); // False (разные ссылки)
// Сравнение значений (не ссылок)
string c = "HELLO".ToLower(); // Создается новая строка "hello"
Console.WriteLine(a == c); // True (значения равны)
Итог: Несмотря на особое поведение, string — это полноценный ссылочный тип, и это важно понимать для управления памятью и производительности.