String vs string в C#: в чем разница и что выбрать?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

String и string в C#: одно и то же или нет? Разбор с примерами

Если вы когда-нибудь писали код на C#, то наверняка замечали, что строки можно объявлять двумя способами:

string name = "Анна";
String greeting = "Привет!";

И оба варианта работают. Возникает резонный вопрос: в чем разница между string и String в C#? Это разные типы? Один быстрее? Или это просто причуда разработчиков языка?

Спойлер: разницы нет. Но не всё так просто, как кажется на первый взгляд. Давайте разберемся по-настоящему, чтобы вы не только знали ответ на популярный вопрос со Stack Overflow, но и понимали, почему так сделано и какой вариант лучше использовать в реальных проектах.

Короткий ответ: string — это псевдоним для System.String

В C# ключевое слово string — это всего лишь псевдоним (alias) для класса System.String. Точно так же, как int — это псевдоним для System.Int32, а bool — для System.Boolean.

Когда компилятор видит string, он автоматически подставляет System.String. Это значит, что оба объявления компилируются в один и тот же IL-код:

// Эти две строки абсолютно идентичны на уровне IL
string a = "Hello";
System.String b = "World";

Если вы откроете скомпилированный .dll или .exe через ILSpy или dotPeek, вы не найдете никакой разницы между этими двумя объявлениями.

Но почему тогда существуют оба варианта?

Исторически сложилось, что C# унаследовал синтаксис от C/C++, где string — это не ключевое слово, а класс. Разработчики .NET решили добавить удобные псевдонимы, чтобы код выглядел более естественно и привычно для программистов, пришедших из других языков.

Кроме того, псевдонимы не требуют подключения пространства имен. Чтобы использовать String, нужно либо добавить using System;, либо писать полное имя System.String. С string таких проблем нет — он доступен всегда.

Когда использовать string, а когда String?

Золотое правило, которое поддерживает большинство команд и которое рекомендует Microsoft в документации C#:

  • Используйте string при объявлении переменных, параметров методов, возвращаемых значений — везде, где это ключевое слово работает как тип.
  • Используйте String только при обращении к статическим методам класса (например, String.IsNullOrEmpty()) или при использовании System.String в тех редких случаях, когда нужно явно указать пространство имен.

Почему так? Потому что string — это ключевое слово языка, оно выделяется цветом в IDE и сразу понятно, что это строка. String — это просто имя класса, и его проще спутать с другими классами.

Пример хорошего стиля

// Объявление переменной (используем string)
string userName = "Иван";

// Вызов статического метода (используем String)
if (String.IsNullOrEmpty(userName))
{
    Console.WriteLine("Имя не может быть пустым");
}

// Параметр метода (используем string)
public void Greet(string name)
{
    Console.WriteLine($"Привет, {name}!");
}

А есть ли разница в производительности?

Многие разработчики задаются вопросом: может быть, string работает быстрее, чем String? Или наоборот?

Ответ: разницы в производительности нет. Никакой. Абсолютно. После компиляции оба варианта превращаются в одинаковый IL-код. Время выполнения, использование памяти, скорость работы — всё идентично.

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

Скрытые нюансы: когда String может сбить с толку

Хотя с точки зрения языка string и String — одно и то же, есть пара моментов, где использование String может привести к путанице.

1. Подключение пространства имен

Если вы напишете String без using System;, компилятор выдаст ошибку:

// Ошибка CS0246: не удалось найти тип или имя пространства имен "String"
String text = "Тест";

С string такой проблемы нет — он всегда доступен.

2. Путаница с собственными классами

Если в вашем проекте есть класс с именем String (например, в другом пространстве имен), то использование String может привести к конфликту имен. string всегда однозначно указывает на System.String.

String vs string в C#: что говорят реальные проекты?

Я проанализировал код нескольких популярных open-source проектов на C# (ASP.NET Core, Entity Framework Core, Roslyn) — везде используется string для объявления переменных и String только для статических методов. Это стандарт индустрии.

Даже в самом фреймворке .NET исходный код написан по тому же принципу. Например, в исходниках System.Console:

public static void WriteLine(string value)
{
    // ...
}

Но внутри этого же метода для вызова статики используется String:

if (String.IsNullOrEmpty(value))
{
    // ...
}

Практический пример: когда знание разницы спасает от ошибки

Представьте ситуацию: вы работаете с рефлексией и пытаетесь получить тип строки:

Type t1 = typeof(string);
Type t2 = typeof(String);

Console.WriteLine(t1 == t2); // True

Оба вызова возвращают System.String. Но если вы попытаетесь использовать typeof(string) в атрибутах или в выражениях, где требуется константа, — string будет работать, а String может потребовать дополнительных действий.

Ещё один интересный момент — в nullable-контексте. Оба типа поддерживают nullable-аннотации одинаково:

string? nullableString = null;  // Работает
String? nullableString2 = null; // Тоже работает

Никакой разницы.

Мифы о string и String в C#

Давайте развеем несколько популярных заблуждений, которые до сих пор гуляют по форумам: