Tutorial: Migrar o código existente com tipos de referência anuláveisTutorial: Migrate existing code with nullable reference types

O C# 8 introduz tipos de referência que permitem valor nulo que complementam os tipos de referência da mesma maneira que os tipos de valor que permitem valor nulo complementam os tipos de valor.C# 8 introduces nullable reference types, which complement reference types the same way nullable value types complement value types. Para declarar que uma variável é um tipo de referência que permite valor nulo, anexe um ? ao tipo.You declare a variable to be a nullable reference type by appending a ? to the type. Por exemplo, string? representa uma string que permite valor nulo.For example, string? represents a nullable string. Você pode usar esses novos tipos para expressar mais claramente sua intenção de design: algumas variáveis devem sempre ter um valor, outras podem ter um valor ausente.You can use these new types to more clearly express your design intent: some variables must always have a value, others may be missing a value. Quaisquer variáveis existentes de um tipo de referência seriam interpretadas como um tipo de referência não anulável.Any existing variables of a reference type would be interpreted as a non-nullable reference type.

Neste tutorial, você aprenderá a:In this tutorial, you'll learn how to:

  • Habilitar verificações de referência nula enquanto trabalha com o código.Enable null reference checks as you work with code.
  • Diagnosticar e corrigir avisos diferentes relacionados a valores nulos.Diagnose and correct different warnings related to null values.
  • Gerenciar a interface entre contextos habilitados para anulável e desabilitados para anulável.Manage the interface between nullable enabled and nullable disabled contexts.
  • Controlar contextos de anotação anuláveis.Control nullable annotation contexts.

Pré-requisitosPrerequisites

Você precisará configurar seu computador para executar o .NET Core, incluindo o C# compilador 8,0.You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. O C# compilador 8 está disponível a partir do Visual Studio 2019 versão 16,3 ou do SDK do .NET Core 3,0.The C# 8 compiler is available starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.

Este tutorial pressupõe que você esteja familiarizado com o C# e .NET, incluindo o Visual Studio ou a CLI do .NET Core.This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.

Explorar o aplicativo de exemploExplore the sample application

O aplicativo de exemplo que você migrará é aplicativo Web leitor de feed RSS.The sample application that you'll migrate is an RSS feed reader web app. Ele lê de um único feed RSS e exibe resumos para os artigos mais recentes.It reads from a single RSS feed and displays summaries for the most recent articles. Você pode clicar em qualquer um dos artigos para visitar o site.You can click on any of the articles to visit the site. O aplicativo é relativamente novo, mas foi escrito antes da disponibilização de tipos de referência anuláveis.The application is relatively new but was written before nullable reference types were available. As decisões de design sobre o aplicativo representam princípios sólidos, mas não aproveitam esse recurso importante de linguagem.The design decisions for the application represented sound principles, but don't take advantage of this important language feature.

O aplicativo de exemplo inclui uma biblioteca de teste de unidade que valida a funcionalidade principal do aplicativo.The sample application includes a unit test library that validates the major functionality of the app. Esse projeto facilitará a atualização com segurança, caso você altere qualquer implementação com base nos avisos gerados.That project will make it easier to upgrade safely, if you change any of the implementation based on the warnings generated. Faça o download do código inicial no repositório dotnet/samples do GitHub.You can download the starter code from the dotnet/samples GitHub repository.

Sua meta ao migrar um projeto deve ser aproveitar os novos recursos de linguagem para poder expressar claramente sua intenção sobre a nulidade de variáveis, e fazer isso de forma que o compilador não gere avisos quando o contexto de anotação anulável e o contexto de aviso anulável estiverem definidos como enabled.Your goal migrating a project should be to leverage the new language features so that you clearly express your intent on the nullability of variables, and do so in such a way that the compiler doesn't generate warnings when you have the nullable annotation context and nullable warning context set to enabled.

Atualizar os projetos para C# 8Upgrade the projects to C# 8

Primeiro, determine o escopo da tarefa de migração.A good first step is to determine the scope of the migration task. Comece atualizando o projeto para C# 8.0 (ou mais recente).Start by upgrading the project to C# 8.0 (or newer). Adicione o elemento LangVersion aos dois arquivos csproj, para o projeto da Web e o projeto de teste de unidade:Add the LangVersion element to both csproj files for the web project and the unit test project:

<LangVersion>8.0</LangVersion>

A atualização da versão da linguagem seleciona C# 8.0, mas não habilita o contexto de anotação anulável ou o contexto de aviso anulável.Upgrading the language version selects C# 8.0, but does not enable the nullable annotation context or the nullable warning context. Recompile o projeto para garantir que ocorra sem avisos.Rebuild the project to ensure that it builds without warnings.

Em seguida, ative o contexto de anotação anulável e veja quantos avisos são gerados.A good next step is to turn on the nullable annotation context and see how many warnings are generated. Adicione o seguinte elemento aos dois arquivos csproj na solução, diretamente abaixo do elemento LangVersion:Add the following element to both csproj files in the solution, directly under the LangVersion element:

<Nullable>enable</Nullable>

Faça uma compilação de teste e observe a lista de avisos.Do a test build, and notice the warning list. Neste aplicativo pequeno, o compilador gera cinco avisos. Provavelmente, você deixaria o contexto de anotação anulável habilitado e iniciaria a correção de avisos de todo o projeto.In this small application, the compiler generates five warnings, so it's likely you'd leave the nullable annotation context enabled and start fixing warnings for the entire project.

Essa estratégia funciona apenas para projetos menores.That strategy works only for smaller projects. Para os projetos maiores, o número de avisos gerados com a habilitação do contexto de anotação anulável em toda a base de código dificulta a correção sistemática dos avisos.For any larger projects, the number of warnings generated by enabling the nullable annotation context for the entire codebase makes it harder to fix the warnings systematically. Para projetos corporativos maiores, convém migrar um projeto de cada vez.For larger enterprise projects, you'll often want to migrate one project at a time. Em cada projeto, migre uma classe ou arquivo por vez.In each project, migrate one class or file at a time.

Os avisos ajudam a descobrir a intenção do design originalWarnings help discover original design intent

Há duas classes que geram vários avisos.There are two classes that generate multiple warnings. Comece com a classe NewsStoryViewModel.Start with the NewsStoryViewModel class. Remova o elemento Nullable dos arquivos csproj para que você possa limitar o escopo dos avisos para as seções do código com as quais você está trabalhando.Remove the Nullable element from both csproj files so that you can limit the scope of warnings to the sections of code you're working with. Abra o arquivo NewsStoryViewModel.cs e adicione as seguintes diretivas para habilitar o contexto de anotação anulável para NewsStoryViewModel e restaure-a seguindo a definição dessa classe:Open the NewsStoryViewModel.cs file and add the following directives to enable the nullable annotation context for the NewsStoryViewModel and restore it following that class definition:

#nullable enable
public class NewsStoryViewModel
{
    public DateTimeOffset Published { get; set; }
    public string Title { get; set; }
    public string Uri { get; set; }
}
#nullable restore

Essas duas diretivas ajudam você a concentrar seus esforços de migração.These two directives help you focus your migration efforts. Os avisos anuláveis são gerados para a área do código na qual você está trabalhando ativamente.The nullable warnings are generated for the area of code you're actively working on. Deixe-os ativos até que você esteja pronto para ativar os avisos de todo o projeto.You'll leave them on until you're ready to turn on the warnings for the entire project. Use restore em vez do valor disable para não desabilitar acidentalmente o contexto após ativar as anotações anuláveis do projeto inteiro.You should use the restore rather than disable value so that you don't accidentally disable the context later when you've turned on nullable annotations for the entire project. Depois de ativar o contexto de anotação anulável para de todo o projeto, remova todas as pragmas #nullable desse projeto.Once you've turned on the nullable annotation context for the entire project, you can remove all the #nullable pragmas from that project.

A classe NewsStoryViewModel é um DTO (objeto de transferência de dados) e duas propriedades são cadeias de caracteres de leitura/gravação:The NewsStoryViewModel class is a data transfer object (DTO) and two of the properties are read/write strings:

public class NewsStoryViewModel
{
    public DateTimeOffset Published { get; set; }
    public string Title { get; set; }
    public string Uri { get; set; }
}

Essas duas propriedades causam CS8618, "Propriedade não anulável não inicializada".These two properties cause CS8618, "Non-nullable property is uninitialized". Está bem claro: as duas propriedades string têm o valor padrão de null quando um NewsStoryViewModel é construído.That's clear enough: both string properties have the default value of null when a NewsStoryViewModel is constructed. O importante é descobrir como os objetos NewsStoryViewModel são construídos.What's important to discover is how NewsStoryViewModel objects are constructed. Examinando essa classe, não é possível determinar se o valor null faz parte do design, ou se esses objetos são definidos como valores não nulos sempre que um é criado.Looking at this class, you can't tell if the null value is part of the design, or if these objects are set to non-null values whenever one is created. As histórias de notícias são criadas no método GetNews da classe NewsService:The news stories are created in the GetNews method of the NewsService class:

ISyndicationItem item = await feedReader.ReadItem();
var newsStory = _mapper.Map<NewsStoryViewModel>(item);
news.Add(newsStory);

Há muita coisa acontecendo no bloco de código anterior.There's quite a bit going on in the preceding block of code. Esse aplicativo usa o pacote NuGet AutoMapper para construir um item de notícias a partir de um ISyndicationItem.This application uses the AutoMapper NuGet package to construct a news item from an ISyndicationItem. Você descobriu que os itens de notícias são construídos, e as propriedades são definidas nessa instrução.You've discovered that the news story items are constructed and the properties are set in that one statement. Isso significa que o design do NewsStoryViewModel indica que essas propriedades nunca devem ter o valor null.That means the design for the NewsStoryViewModel indicates that these properties should never have the null value. Essas propriedades devem ser tipos de referência não anuláveis.These properties should be nonnullable reference types. Isso expressa melhor a intenção do design original.That best expresses the original design intent. Na verdade, qualquer NewsStoryViewModel é corretamente instanciada com valores não nulos.In fact, any NewsStoryViewModel is correctly instantiated with non-null values. Isso torna o código de inicialização a seguir uma correção válida:That makes the following initialization code a valid fix:

public class NewsStoryViewModel
{
    public DateTimeOffset Published { get; set; }
    public string Title { get; set; } = default!;
    public string Uri { get; set; } = default!;
}

A atribuição de Title e Uri a default, que é null para o tipo string, não altera o comportamento de tempo de execução do programa.The assignment of Title and Uri to default which is null for the string type doesn't change the runtime behavior of the program. O NewsStoryViewModel ainda é construído com valores nulos, mas agora o compilador não retorna avisos.The NewsStoryViewModel is still constructed with null values, but now the compiler reports no warnings. O operador que tolera valores nulos, o caractere ! logo após a expressão default informa ao compilador que a expressão anterior não é nula.The null-forgiving operator, the ! character following the default expression tells the compiler that the preceding expression is not null. Essa técnica pode ser conveniente quando outras alterações forçarem mudanças muito maiores em uma base de código, mas, neste aplicativo, há uma solução relativamente rápida e mais adequada: Torne o NewsStoryViewModel um tipo imutável, onde todas as propriedades são definidas no construtor.This technique may be expedient when other changes force much larger changes to a code base, but in this application there is a relatively quick and better solution: Make the NewsStoryViewModel an immutable type where all the properties are set in the constructor. Faça estas alterações em NewsStoryViewModel:Make the following changes to the NewsStoryViewModel:

#nullable enable
    public class NewsStoryViewModel
    {
        public NewsStoryViewModel(DateTimeOffset published, string title, string uri) =>
            (Published, Title, Uri) = (published, title, uri);

        public DateTimeOffset Published { get; }
        public string Title { get; }
        public string Uri { get; }
    }
#nullable restore

Depois disso, atualize o código que configura o AutoMapper, para que ele use o construtor em vez de definir propriedades.Once that's done, you need to update the code that configures the AutoMapper so that it uses the constructor rather than setting properties. Abra NewsService.cs e procure o seguinte código na parte inferior do arquivo:Open NewsService.cs and look for the following code at the bottom of the file:

public class NewsStoryProfile : Profile
{
    public NewsStoryProfile()
    {
        // Create the AutoMapper mapping profile between the 2 objects.
        // ISyndicationItem.Id maps to NewsStoryViewModel.Uri.
        CreateMap<ISyndicationItem, NewsStoryViewModel>()
            .ForMember(dest => dest.Uri, opts => opts.MapFrom(src => src.Id));
    }
}

O código mapeia as propriedades do objeto ISyndicationItem para as propriedades NewsStoryViewModel.That code maps properties of the ISyndicationItem object to the NewsStoryViewModel properties. Em vez disso, você deseja que o AutoMapper forneça o mapeamento usando um construtor.You want the AutoMapper to provide the mapping using a constructor instead. Substitua o código acima pela seguinte configuração do automapper:Replace the above code with the following automapper configuration:

#nullable enable
    public class NewsStoryProfile : Profile
    {
        public NewsStoryProfile()
        {
            // Create the AutoMapper mapping profile between the 2 objects.
            // ISyndicationItem.Id maps to NewsStoryViewModel.Uri.
            CreateMap<ISyndicationItem, NewsStoryViewModel>()
                .ForCtorParam("uri", opt => opt.MapFrom(src => src.Id));
        }

Note que como essa classe é pequena, e você examinou cuidadosamente, ative a diretiva #nullable enable acima dessa declaração de classe.Notice that because this class is small, and you've examined carefully, you should turn on the #nullable enable directive above this class declaration. A alteração no construtor poderia ter quebrado algo, portanto, vale a pena executar todos os testes e testar o aplicativo antes de prosseguir.The change to the constructor could have broken something, so it's worthwhile to run all the tests and test the application before moving on.

O primeiro conjunto de alterações mostrou como descobrir quando o design original indicou que as variáveis não devem ser definidas como null.The first set of changes showed you how to discover when the original design indicated that variables shouldn't be set to null. A técnica é conhecida como corrigir pela construção.The technique is referred to as correct by construction. Você declara que um objeto e suas propriedades não podem ser null quando ele é construído.You declare that an object and its properties cannot be null when it's constructed. A análise de fluxo do compilador fornece garantia de que essas propriedades não são definidas como null após a construção.The compiler's flow analysis provides assurance that those properties aren't set to null after construction. Observe que esse construtor é chamado pelo código externo, e que o código é indiferente ao anulável.Note that this constructor is called by external code, and that code is nullable oblivious. A nova sintaxe não fornece uma verificação de tempo de execução.The new syntax doesn't provide runtime checking. O código externo pode enganar a análise de fluxo do compilador.External code might circumvent the compiler's flow analysis.

Outras vezes, a estrutura de uma classe fornece dicas sobre diferentes sobre a intenção.Other times, the structure of a class provides different clues to the intent. Abra o arquivo Error.cshtml.cs na pasta Páginas.Open the Error.cshtml.cs file in the Pages folder. O ErrorViewModel contém o seguinte código:The ErrorViewModel contains the following code:

public class ErrorModel : PageModel
{
    public string RequestId { get; set; }

    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

    public void OnGet()
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    }
}

Adicione a diretiva #nullable enable antes da declaração de classe e uma diretiva #nullable restore depois dela.Add the #nullable enable directive before the class declaration, and a #nullable restore directive after it. Você receberá um aviso de que RequestId não foi inicializado.You'll get one warning that RequestId is not initialized. Ao examinar a classe, você deve decidir que a propriedade RequestId deve ser nula em alguns casos.By looking at the class, you should decide that the RequestId property should be null in some cases. A existência da propriedade ShowRequestId indica que é possível faltar valores.The existence of the ShowRequestId property indicates that missing values are possible. Como null é válido, adicione o ? no tipo string para indicar que a propriedade RequestId é um tipo de referência anulável.Because null is valid, add the ? on the string type to indicate the RequestId property is a nullable reference type. A classe final se parece com o seguinte exemplo:The final class looks like the following example:

#nullable enable
    public class ErrorModel : PageModel
    {
        public string? RequestId { get; set; }

        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

        public void OnGet()
        {
            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
        }
    }
#nullable restore

Verifique os usos da propriedade, e você verá que na página associada, a propriedade passa por uma verificação de valor nulo antes da renderização na marcação.Check for the uses of the property, and you see that in the associated page, the property is checked for null before rendering it in markup. Esse é um uso seguro de um tipo de referência anulável, portanto, você concluiu essa classe.That's a safe use of a nullable reference type, so you're done with this class.

Corrigir nulos causa alteraçãoFixing nulls causes change

Com frequência, a correção para um conjunto de avisos cria novos avisos no código relacionado.Frequently, the fix for one set of warnings creates new warnings in related code. Vamos ver os avisos em ação corrigindo a classe index.cshtml.cs.Let's see the warnings in action by fixing the index.cshtml.cs class. Abra o arquivo index.cshtml.cs e examine o código.Open the index.cshtml.cs file and examine the code. Esse arquivo contém o código por trás da página de índice:This file contains the code behind for the index page:

public class IndexModel : PageModel
{
    private readonly NewsService _newsService;

    public IndexModel(NewsService newsService)
    {
        _newsService = newsService;
    }

    public string ErrorText { get; private set; }

    public List<NewsStoryViewModel> NewsItems { get; private set; }

    public async Task OnGet()
    {
        string feedUrl = Request.Query["feedurl"];

        if (!string.IsNullOrEmpty(feedUrl))
        {
            try
            {
                NewsItems = await _newsService.GetNews(feedUrl);
            }
            catch (UriFormatException)
            {
                ErrorText = "There was a problem parsing the URL.";
                return;
            }
            catch (WebException ex) when (ex.Status == WebExceptionStatus.NameResolutionFailure)
            {
                ErrorText = "Unknown host name.";
                return;
            }
            catch (WebException ex) when (ex.Status == WebExceptionStatus.ProtocolError)
            {
                ErrorText = "Syndication feed not found.";
                return;
            }
            catch (AggregateException ae)
            {
                ae.Handle((x) =>
                {
                    if (x is XmlException)
                    {
                        ErrorText = "There was a problem parsing the feed. Are you sure that URL is a syndication feed?";
                        return true;
                    }
                    return false;
                });
            }
        }
    }
}

Adicione a diretiva #nullable enable e você verá dois avisos.Add the #nullable enable directive and you'll see two warnings. Nem a propriedade ErrorText, ou a propriedade NewsItems é inicializada.Neither the ErrorText property nor the NewsItems property is initialized. Um exame dessa classe poderia levar você a acreditar que as duas propriedades devem ser tipos de referência anuláveis: Ambos têm setters privados.An examination of this class would lead you to believe that both properties should be nullable reference types: Both have private setters. Exatamente um é atribuído no método OnGet.Exactly one is assigned in the OnGet method. Antes de fazer alterações, examine os consumidores das duas propriedades.Before making changes, look at the consumers of both properties. Na própria página, o ErrorText é verificado em relação ao valor nulo antes de gerar a marcação dos erros.In the page itself, the ErrorText is checked against null before generating markup for any errors. A coleção NewsItems é verificada com relação a null e verificada para garantir que a coleção tenha itens.The NewsItems collection is checked against null, and checked to ensure the collection has items. Uma correção rápida seria transformar as duas propriedades em tipos de referência anuláveis.A quick fix would be to make both properties nullable reference types. Uma correção melhor seria transformar a coleção em um tipo de referência não anulável e adicionar itens à coleção existente ao recuperar notícias.A better fix would be to make the collection a nonnullable reference type, and add items to the existing collection when retrieving news. A primeira correção é adicionar o ? ao tipo string para o ErrorText:The first fix is to add the ? to the string type for the ErrorText:

public string? ErrorText { get; private set; }

Essa alteração não se propagará pelo outro código, pois qualquer acesso à propriedade ErrorText já foi protegida por verificações de valor nulo.That change won't ripple through other code, because any access to the ErrorText property was already guarded by null checks. Em seguida, inicialize a lista NewsItems e remova a propriedade setter, tornando-a uma propriedade somente leitura:Next, initialize the NewsItems list and remove the property setter, making it a readonly property:

public List<NewsStoryViewModel> NewsItems { get; } = new List<NewsStoryViewModel>();

Isso corrigiu o aviso, mas introduziu um erro.That fixed the warning but introduced an error. Agora, a lista NewsItems foi corrigida pela construção, mas o código que define a lista no OnGet deve ser alterado para coincidir com a nova API.The NewsItems list is now correct by construction, but the code that sets the list in OnGet must change to match the new API. Em vez de uma atribuição, chame AddRange para adicionar os itens de notícias à lista existente:Instead of an assignment, call AddRange to add the news items to the existing list:

NewsItems.AddRange(await _newsService.GetNews(feedUrl));

Usar AddRange em vez de uma atribuição significa que o método GetNews pode retornar um IEnumerable em vez de um List.Using AddRange instead of an assignment means that the GetNews method can return an IEnumerable instead of a List. Isso salva uma alocação.That saves one allocation. Altere a assinatura do método e remova a chamada a ToList, conforme mostra o exemplo de código a seguir:Change the signature of the method, and remove the ToList call, as shown in the following code sample:

public async Task<IEnumerable<NewsStoryViewModel>> GetNews(string feedUrl)
{
    var news = new List<NewsStoryViewModel>();
    var feedUri = new Uri(feedUrl);

    using (var xmlReader = XmlReader.Create(feedUri.ToString(),
           new XmlReaderSettings { Async = true }))
    {
        try
        {
            var feedReader = new RssFeedReader(xmlReader);

            while (await feedReader.Read())
            {
                switch (feedReader.ElementType)
                {
                    // RSS Item
                    case SyndicationElementType.Item:
                        ISyndicationItem item = await feedReader.ReadItem();
                        var newsStory = _mapper.Map<NewsStoryViewModel>(item);
                        news.Add(newsStory);
                        break;

                    // Something else
                    default:
                        break;
                }
            }
        }
        catch (AggregateException ae)
        {
            throw ae.Flatten();
        }
    }

    return news.OrderByDescending(story => story.Published);
}

A alteração da assinatura também interrompe testes de uma das opções.Changing the signature breaks one of tests as well. Abra o arquivo NewsServiceTests.cs na pasta Services do projeto SimpleFeedReader.Tests.Open the NewsServiceTests.cs file in the Services folder of the SimpleFeedReader.Tests project. Navegue até o teste Returns_News_Stories_Given_Valid_Uri e altere o tipo da variável result para IEnumerable<NewsItem>.Navigate to the Returns_News_Stories_Given_Valid_Uri test and change the type of the result variable to IEnumerable<NewsItem>. A alteração do tipo significa que a propriedade Count não está mais disponível. Portanto, substitua a propriedade Count no Assert com uma chamada para Any():Changing the type means the Count property is no longer available, so replace the Count property in the Assert with a call to Any():

// Act
IEnumerable<NewsStoryViewModel> result =
    await _newsService.GetNews(feedUrl);

// Assert
Assert.True(result.Any());

Você também precisará adicionar uma instrução using System.Linq ao início do arquivo.You'll need to add a using System.Linq statement to the beginning of the file as well.

Esse conjunto de alterações destaca uma consideração especial ao atualizar o código que inclui instanciações genéricas.This set of changes highlights special consideration when updating code that includes generic instantiations. Tanto a lista quanto os elementos na lista de tipos não anuláveis.Both the list and the elements in the list of non-nullable types. Um deles ou ambos podem ser tipos anuláveis.Either or both could be nullable types. Todas as declarações a seguir são permitidas:All the following declarations are allowed:

  • List<NewsStoryViewModel>: lista não anulável de modelos de exibição não anuláveis.List<NewsStoryViewModel>: nonnullable list of nonullable view models.
  • List<NewsStoryViewModel?>: lista não anulável de modelos de exibição anuláveis.List<NewsStoryViewModel?>: nonnullable list of nullable view models.
  • List<NewsStoryViewModel>?: lista anulável de modelos de exibição não anuláveis.List<NewsStoryViewModel>?: nullable list of nonnullable view models.
  • List<NewsStoryViewModel?>?: lista anulável de modelos de exibição anuláveis.List<NewsStoryViewModel?>?: nullable list of nullable view models.

Interfaces com código externoInterfaces with external code

Você fez alterações na classe NewsService, então, ative a anotação #nullable enable para essa classe.You've made changes to the NewsService class, so turn on the #nullable enable annotation for that class. Isso não gerará avisos novos.This won't generate any new warnings. No entanto, um exame cuidadoso da classe ajuda a ilustrar algumas das limitações da análise de fluxo do compilador.However, careful examination of the class helps to illustrate some of the limitations of the compiler's flow analysis. Examine o construtor:Examine the constructor:

public NewsService(IMapper mapper)
{
    _mapper = mapper;
}

O parâmetro IMapper é tipado como uma referência não anulável.The IMapper parameter is typed as a nonnullable reference. Ele é chamado pelo código de infraestrutura do ASP.NET Core, portanto, o compilador não sabe que o IMapper nunca será nulo.It's called by ASP.NET Core infrastructure code, so the compiler doesn't really know that the IMapper will never be null. O contêiner de DI (injeção de dependência) do ASP.NET Core padrão gera uma exceção se não puder resolver um serviço necessário, para que o código fique correto.The default ASP.NET Core dependency injection (DI) container throws an exception if it can't resolve a necessary service, so the code is correct. O compilador não consegue validar todas as chamadas para suas APIs públicas, mesmo que seu código seja compilado com contextos de anotação anuláveis habilitados.The compiler can't validate all calls to your public APIs, even if your code is compiled with nullable annotation contexts enabled. Além disso, suas bibliotecas podem ser consumidas por projetos que ainda não aceitaram o uso de tipos de referência anuláveis.Furthermore, your libraries may be consumed by projects that have not yet opted into using nullable reference types. Valide as entradas para APIs públicas, mesmo que você as tenha declarado como tipos não anuláveis.Validate inputs to public APIs even though you've declared them as nonnullable types.

Obter o códigoGet the code

Você corrigiu os avisos identificados na compilação de teste inicial, portanto, agora você pode ativar o contexto de anotação anulável para os dois projetos.You've fixed the warnings you identified in the initial test compile, so now you can turn on the nullable annotation context for both projects. Recompile os projetos; o compilador não relatará nenhum aviso.Rebuild the projects; the compiler reports no warnings. Você pode obter o código do projeto concluído no repositório do GitHub dotnet/samples.You can get the code for the finished project in the dotnet/samples GitHub repository.

Os novos recursos que dão suporte aos tipos de referência anuláveis ajudam você a encontrar e corrigir possíveis erros no modo de manipulação de valores null em seu código.The new features that support nullable reference types help you find and fix potential errors in how you handle null values in your code. A habilitação do contexto de anotação anulável permite que você expresse sua intenção de design: algumas variáveis nunca devem ser nulas, outras variáveis podem conter valores nulos.Enabling the nullable annotation context allows you to express your design intent: some variables should never be null, other variables may contain null values. Esses recursos facilitam a declaração de sua intenção de design.These features make it easier for you to declare your design intent. Da mesma forma, o contexto de aviso anulável instrui o compilador a emitir avisos quando você violar essa intenção.Similarly, the nullable warning context instructs the compiler to issue warnings when you have violated that intent. Esses avisos servirão como orientação para criar atualizações que tornem seu código mais resiliente e menos propensa a lançar uma NullReferenceException durante a execução.Those warnings guide you to make updates that make your code more resilient and less likely to throw a NullReferenceException during execution. Você pode controlar o escopo desses contextos para se concentrar na migração de áreas locais do código, enquanto a base de código restante permanece inalterada.You can control the scope of these contexts so that you can focus on local areas of code to migrate while the remaining codebase is untouched. Na prática, você pode tornar essa tarefa de migração uma parte da manutenção regular das suas classes.In practice, you can make this migration task a part of regular maintenance to your classes. Este tutorial demonstrou o processo para migrar um aplicativo a fim de usar tipos de referência anuláveis.This tutorial demonstrated the process to migrate an application to use nullable reference types. Você pode explorar um exemplo real maior desse processo examinando a solicitação de pull feita por Jon Skeet para incorporar tipos de referência anuláveis em NodaTime.You can explore a larger real-world example of this process by examining the PR Jon Skeet made to incorporate nullable reference types into NodaTime.