0Pricing
C# Academy · Урок

Перенос кодовой базы на NRT

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

«Перенос кодовой базы на NRT» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Сложности миграции

Включение NRT в существующей кодовой базе обычно приводит к появлению сотен предупреждений. Резкий переход рискован. Вместо этого используйте поэтапную миграцию: постепенно включайте предупреждения, исправляйте их файл за файлом и не сбавляйте темп.

Шаг 1: включите только предупреждения

Начните с <Nullable>warnings</Nullable>, а не с enable. Это включает предупреждения, но не считает неаннотированный код ошибочным — безопасное начало миграции.

<!-- Phase 1: warnings only, no breaking change -->
<PropertyGroup>
  <Nullable>warnings</Nullable>
</PropertyGroup>

<!-- Phase 2: full enable per file as you migrate -->
<!-- Phase 3: switch to enable globally when done -->

Шаг 2: включайте по одному файлу

Добавляйте #nullable enable в начало каждого файла по мере работы с ним. Так изменения ограничиваются файлами, которые Вы редактируете сейчас, а проверка изменений становится управляемой.

#nullable enable
// Now this file has full NRT analysis

public class OrderService
{
    private readonly IOrderRepository _repo;
    // Compiler now warns about uninitialized non-nullable fields,
    // unsafe dereferences, and assignment to non-nullable

    public OrderService(IOrderRepository repo) => _repo = repo;
}

// Other files without #nullable enable are still unchecked

Классификация предупреждений

Предупреждения делятся на две категории: которые безопасно подавить (сущности ORM, поля, внедряемые через DI) и настоящие ошибки (значения, действительно равные null и разыменовываемые в коде). Перед подавлением чего-либо определите, к какой категории относится предупреждение.

// Category 1: safe to suppress with null!
// EF Core navigation properties — set by EF, never null in practice
public class Order
{
    public Customer Customer { get; set; } = null!;
}

// Category 2: real bug — must fix
public string GetFullName()
{
    return FirstName + " " + LastName; // LastName was string? -- BUG!
}

Исправление предупреждения конструктора CS8618

CS8618 возникает, когда свойство, не допускающее null, не задано в конструкторе. Предпочтительное решение — сделать его обязательным параметром конструктора. Используйте = null! только для значений, задаваемых фреймворком.

// BEFORE (CS8618)
public class Product
{
    public string Name { get; set; }   // warning
    public Category Category { get; set; } // warning
}

// AFTER — constructor required:
public class Product
{
    public string Name { get; set; }
    public Category Category { get; set; }

    public Product(string name, Category category)
    {
        Name = name;
        Category = category;
    }
}

Работа с устаревшими API

Сторонние или устаревшие API могут не иметь аннотаций. Их возвращаемые типы являются неопределёнными — не указывают, допускается ли null. Для явного обозначения присваивайте результаты таких вызовов переменным, допускающим null.

// Legacy API returns 'string' but might be null (oblivious type)
string? legacyResult = OldLibrary.GetValue(); // store as nullable
if (legacyResult is null) return;

// Or convert at the boundary:
string safe = OldLibrary.GetValue() ?? "";

// For third-party types, check if they have NRT annotations:
// NuGet packages often add nullable annotations in newer versions

Использование #pragma для подавления отдельных предупреждений

Если предупреждение действительно является ложным срабатыванием, а = null! выглядит слишком шумно, используйте #pragma warning disable, ограничив его действие конкретной строкой.

// Suppress for a specific case with explanation:
#pragma warning disable CS8618 // ORM populates this via reflection
public DbSet<Product> Products { get; set; }
#pragma warning restore CS8618

// Or inline with a comment:
public DbSet<Order> Orders { get; set; } = null!; // set by EF Core

Преобразование предупреждений NRT в ошибки

После исправления всех предупреждений в файле добавьте <WarningsAsErrors>Nullable</WarningsAsErrors> (или включите проверку в CI), чтобы предотвратить регрессии: любая новая проблема с nullable-кодом приведёт к сбою сборки.

<!-- After full migration: treat nullable warnings as build errors -->
<PropertyGroup>
  <Nullable>enable</Nullable>
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  <!-- Or selectively: -->
  <!-- <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors> -->
</PropertyGroup>

Аннотирование общедоступных API

Если Вашу библиотеку используют другие разработчики, аннотации NRT становятся частью контракта её общедоступного API. Возвращайте T?, если результат может быть равен null, и T, если это гарантированно невозможно.

public interface IProductService
{
    // Contract: FindById MAY return null, GetById never does
    Product? FindById(int id);
    Product  GetById(int id);  // throws if not found

    // Collection: never null (may be empty)
    IReadOnlyList<Product> GetAll();

    // String: may be empty but not null
    string GetSummary(int id);
}

Метрики и отслеживание миграции

Отслеживайте прогресс, подсчитывая файлы с #nullable enable или выполняя в CI команду dotnet build 2>&1 | grep CS86. Установите целевую дату завершения миграции всего проекта.

# Count NRT warnings in current build
dotnet build 2>&1 | grep -c 'CS860[0-9]\|CS861[0-9]\|CS862[0-9]'

# List files still missing #nullable enable
grep -rL '#nullable enable' src/ --include='*.cs'

# Track in CI: fail if warning count increases
# Set a budget: warnings <= N, where N decreases each sprint

Быстрая проверка

Что означает присваивание = null! свойству, не допускающему null?

Повторение: миграция на NRT

Основные выводы:

  • Используйте поэтапную миграцию: режим предупреждений → включение для каждого файла → глобальное включение
  • Отличайте настоящие ошибки (исправляйте их) от шаблонов ORM/DI (используйте = null!)
  • Исправляйте CS8618, требуя значения в конструкторах, а не подавляя предупреждение
  • Присваивайте результаты устаревших API переменным типа T?, чтобы явно обозначить возможность null
  • Считайте предупреждения о nullable ошибками в CI, чтобы предотвратить регрессии
  • Аннотированные общедоступные API становятся понятными контрактами для пользователей

Часто задаваемые вопросы

Урок «Перенос кодовой базы на NRT» бесплатный?

Да — полный текст урока «Перенос кодовой базы на NRT» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Перенос кодовой базы на NRT»?

Применяйте поэтапную стратегию переноса: включайте предупреждения, аннотируйте API, исправляйте проблемы и избегайте ложных срабатываний. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

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

Сколько времени занимает урок «Перенос кодовой базы на NRT»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Включение и понимание NRT
  2. Аннотации: ?, !, MaybeNull и NotNull
  3. Операторы условного объединения и объединения с null
  4. Перенос кодовой базы на NRT
← Назад к C# Academy