Nullable reference

Тема дорожной карты · .NET / C# Developer

Nullable reference types (NRT) — фича C# 8, которая делает обработку null частью системы типов. До NRT любая ссылочная переменная могла быть null, и компилятор не предупреждал. С NRT тип string обозначает «гарантированно не null», а string? — «может быть null». Компилятор статически анализирует код и выдаёт предупреждения, когда null-значение попадает туда, где не ожидается. По сути — статический null-safety на уровне типов, аналог Option<T> из ML-языков, только встроенный в существующий тип.

Как это работает

Включается через <Nullable>enable</Nullable> в .csproj или #nullable enable в файле. Компилятор отслеживает «flow analysis» — на каждой инструкции вычисляет, может ли переменная быть null, и сравнивает с типом. Атрибуты разметки ([NotNull], [MaybeNull], [NotNullWhen(true)], [MemberNotNull]) позволяют выразить контракты, которые компилятор сам не вывел бы. Операторы ! (null-forgiving) подавляют предупреждение в местах, где разработчик уверен. Default-значения для типа T?default(T) для value types и null для reference types.

Когда применять

Включайте NRT во всех новых проектах с первого дня — стоимость нулевая после привыкания, а инциденты с NullReferenceException практически исчезают. Для legacy-проектов выбирайте миграцию по файлам: #nullable enable в одном файле за раз, исправляйте предупреждения, двигайтесь дальше. Не отключайте NRT через ! массово — это превращает фичу в обвес, не дающий пользы. Лучше явно проверить null или указать в типе.

Типичные ошибки

Массовое подавление через ! — теряется вся ценность фичи. Игнорирование [NotNullWhen] атрибутов в string.IsNullOrEmpty и Try* методах — компилятор не выведет null-safety, если контракт не выражен. Использование string.Empty вместо null для «отсутствующего значения» — теряется семантическая разница между «пустой строкой» и «значение не передано». Включение NRT без обновления интерфейсов API — клиенты внезапно получают предупреждения на каждом обращении. Игнорирование default! в generic-классах для полей — компилятор сообщит «non-nullable field is uninitialized» на каждом конструкторе.

Связанные понятия

Полезные ресурсы