Migrando uma base de código para NRT
Aplique uma estratégia de migração em etapas: ative os avisos, anote APIs, corrija problemas e evite falsos positivos.
Migrando uma base de código para NRT é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
O desafio da migração
Habilitar NRT em uma base de código existente normalmente produz centenas de avisos. Uma abordagem de mudança total de uma só vez é arriscada. Em vez disso, use uma migração em fases: habilite os avisos gradualmente, corrija-os arquivo por arquivo e nunca perca o ritmo.
Etapa 1: habilitar somente os avisos
Comece com <Nullable>warnings</Nullable> em vez de enable. Isso ativa os avisos sem tratar o código não anotado como erros — um ponto de partida seguro.
<!-- 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 -->Etapa 2: habilitar por arquivo
Adicione #nullable enable ao início de cada arquivo conforme trabalhar nele. Isso limita as alterações aos arquivos que você está editando ativamente, tornando as revisões mais fáceis de gerenciar.
#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 uncheckedCategorizando os avisos
Os avisos se dividem em duas categorias: seguros para suprimir (entidades de ORM, campos injetados por DI) e bugs reais (valores que são de fato nulos e estão sendo desreferenciados). Diferencie essas categorias antes de suprimir qualquer coisa.
// 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!
}Corrigindo o aviso de construtor CS8618
CS8618 é emitido quando uma propriedade não anulável não é definida no construtor. A correção preferida é exigir seu valor no construtor. Use = null! somente para valores definidos pela estrutura.
// 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;
}
}Lidando com APIs legadas
APIs de terceiros ou legadas podem não ter anotações. Seus tipos de retorno são indiferentes à nulidade (nem anuláveis nem não anuláveis). Atribua os resultados a variáveis anuláveis para deixar isso explícito.
// 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 versionsUsando #pragma para suprimir avisos específicos
Quando um aviso é genuinamente um falso positivo e = null! parece excessivamente ruidoso, use #pragma warning disable limitado à linha específica.
// 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 CoreTratando avisos de NRT como erros
Depois que todos os avisos forem corrigidos em um arquivo, adicione <WarningsAsErrors>Nullable</WarningsAsErrors> (ou use a aplicação dessa regra na integração contínua) para evitar regressões — qualquer novo problema de nulidade fará a compilação falhar.
<!-- After full migration: treat nullable warnings as build errors -->
<PropertyGroup>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- Or selectively: -->
<!-- <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors> -->
</PropertyGroup>Anotando APIs públicas
Quando sua biblioteca é consumida por outras pessoas, as anotações de NRT passam a fazer parte do contrato da sua API pública. Retorne T? quando o resultado puder ser nulo; retorne T quando houver garantia de que ele não será nulo.
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);
}Métricas e acompanhamento da migração
Acompanhe o progresso contando os arquivos com #nullable enable ou executando dotnet build 2>&1 | grep CS86 na integração contínua. Defina uma data-alvo para concluir a migração de todo o projeto.
# 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 sprintVerificação rápida
O que a atribuição = null! em uma propriedade não anulável comunica?
Recapitulação: migrando para NRT
Principais conclusões:
- Use uma migração em fases: modo de avisos → habilitação por arquivo → habilitação global
- Diferencie bugs reais (corrija-os) de padrões de ORM/DI (use
= null!) - Corrija CS8618 exigindo valores nos construtores, não suprimindo o aviso
- Atribua os resultados de APIs legadas a variáveis
T?para deixar a nulidade explícita - Trate avisos de nulidade como erros na integração contínua para evitar regressões
- APIs públicas anotadas tornam-se contratos claros para os consumidores
Perguntas Frequentes
A aula “Migrando uma base de código para NRT” é grátis?
Sim — o texto completo de “Migrando uma base de código para NRT” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “Migrando uma base de código para NRT”?
Aplique uma estratégia de migração em etapas: ative os avisos, anote APIs, corrija problemas e evite falsos positivos. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Migrando uma base de código para NRT”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Ativação e compreensão de NRT
- Anotações: ?, !, MaybeNull e NotNull
- Operadores condicionais e de coalescência de nulo
- Migrando uma base de código para NRT