String — это ссылочный или значимый тип данных в C#?

«String — это ссылочный или значимый тип данных в C#?» — вопрос из категории C# Core, который задают на 36% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В 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 — это полноценный ссылочный тип, и это важно понимать для управления памятью и производительности.