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#
Давайте развеем несколько популярных заблуждений, которые до сих пор гуляют по форумам:
- Миф:
String