Найти в Дзене

Строки в C#: Разбираемся в природе String и путанице с string

Каждый, кто начинает изучать C#, довольно быстро сталкивается со строками. Это фундаментальный тип данных, без которого не обходится практически ни одна программа. Мы пишем string name = "Иван"; и не задумываемся о том, что скрывается за этим простым действием. Однако, стоит копнуть чуть глубже, и у новичков (да и у опытных разработчиков, которые редко заглядывают в документацию) возникает закономерный вопрос: А в чем разница между string и String? И главное, почему говорят, что String — это класс, но ведет он себя порой как значение? Давайте раз и навсегда расставим все точки над i. Первое и самое важное, что нужно усвоить: в C# строка является ссылочным типом (reference type). Это значит, что когда вы создаете строку, в управляемой куче (heap) выделяется память под ее символы, а переменная, которой вы оперируете, хранит лишь ссылку (адрес) на эту область памяти. // Переменная s хранит не сами символы "Привет", а ссылку на них в куче string s = "Привет"; Почему это важно? Потому что э
Оглавление

Каждый, кто начинает изучать C#, довольно быстро сталкивается со строками. Это фундаментальный тип данных, без которого не обходится практически ни одна программа. Мы пишем string name = "Иван"; и не задумываемся о том, что скрывается за этим простым действием.

Однако, стоит копнуть чуть глубже, и у новичков (да и у опытных разработчиков, которые редко заглядывают в документацию) возникает закономерный вопрос: А в чем разница между string и String? И главное, почему говорят, что String — это класс, но ведет он себя порой как значение?

Давайте раз и навсегда расставим все точки над i.

Часть 1. Строка — это класс (и точка)

Первое и самое важное, что нужно усвоить: в C# строка является ссылочным типом (reference type). Это значит, что когда вы создаете строку, в управляемой куче (heap) выделяется память под ее символы, а переменная, которой вы оперируете, хранит лишь ссылку (адрес) на эту область памяти.

// Переменная s хранит не сами символы "Привет", а ссылку на них в куче
string s = "Привет";

Почему это важно? Потому что это объясняет многие нюансы поведения строк, например, их неизменяемость (immutability). Если строка — это объект в куче, то для обеспечения надежности и производительности среда CLR гарантирует, что после создания строки вы не сможете изменить ее содержимое. Любая операция, которая выглядит как изменение строки (например, замена символа или конкатенация), на самом деле создает новый объект в куче.

В этом контексте String — это просто класс из пространства имен System. Полное имя типа — System.String. Это стандартный класс .NET, определенный в базовой библиотеке классов (BCL).

Часть 2. Великое противостояние: string против String

Итак, мы выяснили, что String — это класс. Но откуда тогда взялся string с маленькой буквы?

Ответ прост и элегантен: string — это просто псевдоним (алиас, синоним) класса System.String в языке C#.

Это синтаксический сахар, придуманный создателями языка для удобства. Точно так же, как int — это псевдоним для System.Int32, а bool — для System.Boolean.

  • string — это ключевое слово C#. Оно используется для объявления переменных в стиле, привычном для C-подобных языков.
  • String — это имя типа из .NET. Оно принадлежит общеязыковой спецификации (CLS) и понятно любому .NET-языку (VB.NET, F#), даже если в них нет ключевого слова string.
// Эти две строки кода абсолютно идентичны для компилятора
string a = "Hello";
String b = "Hello"; // Требуется using System; или полное имя System.String

Компилятор C# воспринимает их как один и тот же тип.

Часть 3. Почему же строка ведет себя как значение?

Здесь кроется главный источник путаницы. Если строка — это класс (ссылочный тип), то при передаче в метод она должна передаваться по ссылке. Изменения, сделанные внутри метода, должны влиять на оригинал. Но на практике это не так.

Почему original не изменился?

Именно из-за неизменяемости и механизма передачи параметров.

  1. В момент вызова метода MakeUppercase(original) переменная str получает копию ссылки. Теперь и original, и str указывают на одну и ту же строку "hello" в куче.
  2. Внутри метода мы вызываем str.ToUpper(). Этот метод не может изменить исходный объект (так как он неизменяем). Вместо этого он создает новый объект в куче — строку "HELLO".
  3. Затем мы присваиваем переменной str новый адрес — ссылку на новую строку.
  4. Метод завершается. Переменная original по-прежнему хранит старую ссылку на старую строку "hello", потому что мы меняли только копию ссылки.

Если бы строка была значимым типом (struct), в метод передавалась бы копия самой структуры, и это тоже не привело бы к изменению оригинала. Но в случае со строкой механизм иной — копируется ссылка, а объект в куче остается неизменным.

Часть 4. Когда писать String, а когда string?

С точки зрения IL-кода (промежуточного языка), разницы нет никакой. Однако в сообществе C#-разработчиков сложились негласные правила стиля (которые, кстати, поддерживает и анализатор кода Microsoft):

1. Для объявления переменных используйте string.

Это делает код более естественным для C# и единообразным с другими примитивами (int, bool).

string firstName = "Дмитрий";

2. Используйте String, когда обращаетесь к статическим методам класса.

Это подчеркивает, что вы работаете с типом .NET.

-2

3. Используйте String в названиях методов, если имя типа конфликтует с вашей переменной.

Это редкость, но бывает.

// Допустим, у вас есть переменная string (плохая идея называть так переменные)
// Чтобы вызвать метод класса, придется писать @string или полное имя
string @string = "test";
bool check = String.IsNullOrEmpty(@string);

Заключение

Итак, давайте подведём итоги:

  • String (или System.String) — это класс, ссылочный тип, основа всех строк в .NET.
  • string — это ключевое слово C#, удобный псевдоним для System.String.
  • Строки неизменяемы. Любая операция "изменения" строки создает новый объект.
  • Из-за неизменяемости и механизма передачи копии ссылки, строки ведут себя как значимые типы при передаче в методы, хотя таковыми не являются.

Понимание этого различия — важный шаг от новичка к профессионалу, который позволяет писать эффективный и надежный код, избегая неожиданных сюрпризов при работе с текстовыми данными.

На этом всё. Подписывайтесь на канал, чтобы ничего не пропустить.