Tutorial: Migrieren vorhandenen Codes mit Verweistypen, die NULL-Werte zulassenTutorial: Migrate existing code with nullable reference types

C# 8 führt Verweistypen, die NULL-Werte zulassen ein, die Verweistypen auf die gleiche Weise ergänzen, wie NULL-Werte zulassenden Werttypen Werttypen ergänzen.C# 8 introduces nullable reference types, which complement reference types the same way nullable value types complement value types. Sie deklarieren eine Variable zu einem Verweistyp, der NULL-Werte zulässt, indem Sie ? an den Typen anfügen.You declare a variable to be a nullable reference type by appending a ? to the type. Beispielsweise stellt string? eine string dar, die NULL-Werte zulässt.For example, string? represents a nullable string. Mit diesen neuen Typen können Sie Ihre Entwurfsabsicht besser zum Ausdruck bringen: Einige Variablen müssen immer einen Wert haben, bei anderen kann ein Wert fehlen.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. Alle vorhandenen Variablen eines Verweistyps würden als NULL-Werte zulassende Verweistypen interpretiert.Any existing variables of a reference type would be interpreted as a non-nullable reference type.

In diesem Tutorial lernen Sie, wie die folgenden Aufgaben ausgeführt werden:In this tutorial, you'll learn how to:

  • Aktivieren von NULL-Verweis-Überprüfungen beim Arbeiten mit Code.Enable null reference checks as you work with code.
  • Diagnostizieren und Korrigieren verschiedener Warnungen im Zusammenhang mit NULL-Werten.Diagnose and correct different warnings related to null values.
  • Verwalten der Schnittstelle zwischen NULL-Werte zulassenden und NULL-Werte nicht zulassenden Kontexten.Manage the interface between nullable enabled and nullable disabled contexts.
  • Steuern NULL-Werte zulassender Anmerkungskontexte.Control nullable annotation contexts.

Erforderliche KomponentenPrerequisites

Sie müssen Ihren Computer zur Ausführung von .NET Core einrichten, einschließlich des C# 8.0-Compilers.You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. Der C# 8-Compiler steht ab Visual Studio 2019 Version 16.3 oder mit dem .NET Core 3.0 SDK zur Verfügung.The C# 8 compiler is available starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.

In diesem Tutorial wird vorausgesetzt, dass Sie C# und .NET, einschließlich Visual Studio oder die .NET Core-CLI kennen.This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.

Untersuchen der BeispielanwendungExplore the sample application

Die Beispielanwendung, die Sie migrieren, ist eine RSS-Feed-Reader-Web-App.The sample application that you'll migrate is an RSS feed reader web app. Sie liest aus einem einzelnen RSS-Feed und zeigt Zusammenfassungen für die neuesten Artikel an.It reads from a single RSS feed and displays summaries for the most recent articles. Sie können einen der Artikel auswählen, um auf die Website zuzugreifen.You can select any of the articles to visit the site. Die Anwendung ist relativ neu, wurde jedoch geschrieben, bevor NULL-Werte zulassende Verweistypen verfügbar waren.The application is relatively new but was written before nullable reference types were available. Die Entwurfsentscheidungen für die Anwendung stellten bewährte Prinzipien dar, nutzen diese wichtige Sprachfunktion jedoch nicht.The design decisions for the application represented sound principles, but don't take advantage of this important language feature.

Die Beispielanwendung enthält eine Komponententestbibliothek, die die wichtigsten Funktionen der App überprüft.The sample application includes a unit test library that validates the major functionality of the app. Das Projekt wird die sichere Aktualisierung erleichtern, wenn Sie Teile der Implementierung entsprechend der generierten Warnungen ändern.That project will make it easier to upgrade safely, if you change any of the implementation based on the warnings generated. Sie können den Startercode aus dem Repository dotnet/samples auf GitHub herunterladen.You can download the starter code from the dotnet/samples GitHub repository.

Ihr Ziel beim Migrieren eines Projekts sollte die Nutzung neuer Sprachfeatures sein, sodass Sie deutlich Ihre Absicht bezüglich des Zulassens von NULL-Werten bei Variablen ausdrücken, und zwar so, dass der Compiler keine Warnungen generiert, wenn Sie für den NULL-Werte zulassenden Anmerkungskontext und den NULL-Werte zulassenden Warnungskontext enabled festlegen.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.

Aktualisieren der Projekte auf C# 8Upgrade the projects to C# 8

Ein guter erster Schritt ist, den Bereich der Migrationsaufgabe zu bestimmen.A good first step is to determine the scope of the migration task. Beginnen Sie mit dem Upgrade des Projekts auf C# 8.0 (oder höher).Start by upgrading the project to C# 8.0 (or newer). Fügen Sie das LangVersion-Element beiden CSPROJ-Dateien für das Webprojekt und das Komponententestprojekt hinzu:Add the LangVersion element to both csproj files for the web project and the unit test project:

<LangVersion>8.0</LangVersion>

Beim Aktualisieren der Sprachversion wird C# 8.0 ausgewählt, aber dies aktiviert nicht den NULL-Werte zulassenden Anmerkungskontext oder den NULL-Werte zulassenden Warnungskontext.Upgrading the language version selects C# 8.0, but does not enable the nullable annotation context or the nullable warning context. Erstellen Sie das Projekt neu, um sicherzustellen, dass es ohne Warnungen erstellt wird.Rebuild the project to ensure that it builds without warnings.

Ein guter nächster Schritt ist, den NULL-Werte zulassenden Anmerkungskontext zu aktivieren und zu sehen, wie viele Warnungen generiert werden.A good next step is to turn on the nullable annotation context and see how many warnings are generated. Fügen Sie das folgende Element beiden CSPROJ-Dateien in der Projektmappe hinzu, direkt unterhalb des LangVersion-Elements:Add the following element to both csproj files in the solution, directly under the LangVersion element:

<Nullable>enable</Nullable>

Führen Sie einen Testbuild durch, und beachten Sie die Liste der Warnungen.Do a test build, and notice the warning list. In dieser kleinen Anwendung generiert der Compiler fünf Warnungen, daher sollten Sie den NULL-Werte zulassenden Anmerkungskontext aktiviert lassen und beginnen, Warnungen für das gesamte Projekt zu beheben.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.

Diese Strategie funktioniert nur bei kleineren Projekten.That strategy works only for smaller projects. Bei größeren Projekten erschwert die Anzahl der Warnungen, die durch das Aktivieren des NULL-Werte zulassenden Anmerkungskontexts für die gesamte Codebase generiert werden, die systematische Behebung der Warnungen.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. Für größere Enterprise-Projekte müssen Sie häufig jeweils ein Projekt migrieren.For larger enterprise projects, you'll often want to migrate one project at a time. In jedem Projekt migrieren Sie jeweils eine Klasse oder eine Datei.In each project, migrate one class or file at a time.

Warnungen tragen dazu bei, die ursprüngliche Entwurfsabsicht zu ermittelnWarnings help discover original design intent

Es gibt zwei Klassen, die mehrere Warnungen generieren.There are two classes that generate multiple warnings. Beginnen Sie mit der NewsStoryViewModel-Klasse.Start with the NewsStoryViewModel class. Entfernen Sie das Nullable-Element aus beiden CSPROJ-Dateien, damit Sie den Bereich der Warnungen auf die Abschnitte des Codes beschränken können, mit denen Sie arbeiten.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. Öffnen Sie die NewsStoryViewModel.cs-Datei, und fügen Sie die folgenden Anweisungen zum Aktivieren des NULL-Werte zulassenden Anmerkungskontexts für das NewsStoryViewModel hinzu, und stellen Sie es nach dieser Klassendefinition wieder her: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

Mit diesen beiden Anweisungen können Sie sich auf Ihre Migration konzentrieren.These two directives help you focus your migration efforts. Die NULL-Werte zulassenden Warnungen werden für den Bereich des Codes generiert, an dem Sie aktiv arbeiten.The nullable warnings are generated for the area of code you're actively working on. Sie müssen sie aktiviert lassen, bis Sie bereit sind, die Warnungen für das gesamte Projekt zu aktivieren.You'll leave them on until you're ready to turn on the warnings for the entire project. Verwenden Sie den Wert restore statt disable, sodass Sie später nicht versehentlich den Kontext deaktivieren, wenn Sie NULL-Werte zulassende Anmerkungen für das gesamte Projekt aktiviert haben.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. Nachdem Sie für das gesamte Projekt den NULL-Werte zulassenden Anmerkungskontext aktiviert haben, können Sie alle #nullable-Pragmas aus dem Projekt entfernen.Once you've turned on the nullable annotation context for the entire project, you can remove all the #nullable pragmas from that project.

Die NewsStoryViewModel-Klasse ist ein Datenübertragungsobjekt (Data Transfer Object, DTO), und zwei der Eigenschaften sind Lese-/Schreibzeichenfolgen: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; }
}

Diese beiden Eigenschaften lösen CS8618 aus: „Initialisierung der NULL-Werte nicht zulassenden Eigenschaft wird aufgehoben“.These two properties cause CS8618, "Non-nullable property is uninitialized". Das ist deutlich genug: Beide string-Eigenschaften weisen den Standardwert null auf, wenn ein NewsStoryViewModel erstellt wird.That's clear enough: both string properties have the default value of null when a NewsStoryViewModel is constructed. Es ist wichtig, zu ermitteln, wie NewsStoryViewModel-Objekte erstellt werden.What's important to discover is how NewsStoryViewModel objects are constructed. Wenn Sie diese Klasse betrachten, ist nicht erkennbar, ob der null-Wert Teil des Entwurfs ist, oder ob diese Objekte bei ihrer Erstellung auf Werte ungleich Null festgelegt werden.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. Die neuen Storys werden in der GetNews-Methode der NewsService-Klasse erstellt: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);

Im vorherigen Codeblock ist einiges los.There's quite a bit going on in the preceding block of code. Diese Anwendung verwendet das AutoMapper-NuGet-Paket zum Erstellen eines Nachrichtenelements aus einem ISyndicationItem.This application uses the AutoMapper NuGet package to construct a news item from an ISyndicationItem. Sie haben festgestellt, dass in dieser einen Anweisung die Nachrichtenelemente erstellt und die Eigenschaften festgelegt werden.You've discovered that the news story items are constructed and the properties are set in that one statement. Das bedeutet, dass der Entwurf für das NewsStoryViewModel angibt, dass diese Eigenschaften nie den Wert null haben sollten.That means the design for the NewsStoryViewModel indicates that these properties should never have the null value. Diese Eigenschaften sollten Nullwerte nicht zulassende Verweistypen sein.These properties should be nonnullable reference types. Das drückt am besten die ursprüngliche Entwurfsabsicht aus.That best expresses the original design intent. Jedes NewsStoryViewModel ist in der Tat mit NULL nicht zulassenden Werten ordnungsgemäß instanziiert.In fact, any NewsStoryViewModel is correctly instantiated with non-null values. Das macht den folgenden Initialisierungscode zu einer gültigen Fehlerbehebung: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!;
}

Die Zuweisung von Title und Uri zu default, die null für den string-Typ ist, ändert das Laufzeitverhalten des Programms nicht.The assignment of Title and Uri to default which is null for the string type doesn't change the runtime behavior of the program. Das NewsStoryViewModel ist immer noch mit NULL-Werten erstellt, aber jetzt gibt der Compiler keine Warnungen aus.The NewsStoryViewModel is still constructed with null values, but now the compiler reports no warnings. Der NULL-tolerante Operator, das !-Zeichen, das auf den default-Ausdruck folgt, teilt dem Compiler mit, dass der vorherige Ausdruck nicht NULL ist.The null-forgiving operator, the ! character following the default expression tells the compiler that the preceding expression is not null. Diese Technik kann zweckmäßig sein, wenn andere Änderungen viel größere Änderungen einer Codebasis erzwingen, aber in dieser Anwendung gibt es eine relativ schnelle und bessere Lösung: Machen Sie das NewsStoryViewModel zu einem unveränderlichen Typ, in dem alle Eigenschaften im Konstruktor festgelegt werden.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. Nehmen Sie am NewsStoryViewModel die folgenden Änderungen vor: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

Sobald das geschehen ist, müssen Sie den Code aktualisieren, der den AutoMapper konfiguriert, sodass er den Konstruktor verwendet, anstatt Eigenschaften festzulegen.Once that's done, you need to update the code that configures the AutoMapper so that it uses the constructor rather than setting properties. Öffnen Sie NewsService.cs, und suchen Sie unten in der Datei den folgenden Code: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));
    }
}

Dieser Code weist Eigenschaften des ISyndicationItem-Objekts den NewsStoryViewModel-Eigenschaften zu.That code maps properties of the ISyndicationItem object to the NewsStoryViewModel properties. Sie möchten, dass der AutoMapper die Zuordnung stattdessen mithilfe eines Konstruktors bereitstellt.You want the AutoMapper to provide the mapping using a constructor instead. Ersetzen Sie den obigen Code mit der folgenden Automapper-Konfiguration: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));
        }

Beachten Sie: Da diese Klasse klein ist, und Sie sie sorgfältig untersucht haben, sollten Sie die #nullable enable-Anweisung über dieser Klassendeklaration aktivieren.Notice that because this class is small, and you've examined carefully, you should turn on the #nullable enable directive above this class declaration. Die Änderung am Konstruktor könnte etwas beschädigt haben, darum lohnt es sich, alle Tests auszuführen und die Anwendung zu testen, bevor Sie fortfahren.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.

Der erste Satz von Änderungen zeigte Ihnen, wie Sie ermitteln, wann der ursprüngliche Entwurf anzeigte, dass für Variablen nicht null festgelegt werden sollte.The first set of changes showed you how to discover when the original design indicated that variables shouldn't be set to null. Diese Technik wird als Korrigieren nach Erstellung bezeichnet.The technique is referred to as correct by construction. Sie deklarieren, dass ein Objekt und seine Eigenschaften nicht null sein können, wenn es erstellt wird.You declare that an object and its properties cannot be null when it's constructed. Die Flussanalyse des Compilers bietet die Gewissheit, dass diese Eigenschaften nach der Erstellung nicht auf null gesetzt sind.The compiler's flow analysis provides assurance that those properties aren't set to null after construction. Beachten Sie, dass dieser Konstruktor durch externen Code aufgerufen wird, und dieser Code ignoriert NULL-Werte.Note that this constructor is called by external code, and that code is nullable oblivious. Die neue Syntax bietet keine Runtimeüberprüfung.The new syntax doesn't provide runtime checking. Externer Code könnte die Flussanalyse des Compilers umgehen.External code might circumvent the compiler's flow analysis.

In anderen Fällen bietet die Struktur einer Klasse andere Hinweise zur Absicht.Other times, the structure of a class provides different clues to the intent. Öffnen Sie die Error.cshtml.cs-Datei im Ordner Pages.Open the Error.cshtml.cs file in the Pages folder. Das ErrorViewModel enthält folgenden Code: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;
    }
}

Fügen Sie die #nullable enable-Anweisung vor der Klassendeklaration und eine #nullable restore-Anweisung dahinter hinzu.Add the #nullable enable directive before the class declaration, and a #nullable restore directive after it. Sie erhalten eine Warnung, das RequestId nicht initialisiert ist.You'll get one warning that RequestId is not initialized. Wenn Sie die Klasse betrachten, sollten Sie entscheiden, dass die RequestId-Eigenschaft in einigen Fällen NULL sein sollte.By looking at the class, you should decide that the RequestId property should be null in some cases. Das Vorhandensein der ShowRequestId-Eigenschaft gibt an, dass fehlende Werte möglich sind.The existence of the ShowRequestId property indicates that missing values are possible. Da null gültig ist, fügen Sie ? dem string-Typ hinzu, um anzugeben, dass die RequestId-Eigenschaft ein NULL-Werte zulassender Verweistyp ist.Because null is valid, add the ? on the string type to indicate the RequestId property is a nullable reference type. Die finale Klasse sieht wie im folgenden Beispiel aus: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

Überprüfen Sie die Verwendung der Eigenschaft, und Sie sehen, dass die Eigenschaft auf der entsprechenden Seite vor dem Rendern im Markup auf NULL überprüft wird.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. Das ist eine sichere Verwendung eines NULL-Werte zulassenden Verweistyps, also sind Sie mit dieser Klasse fertig.That's a safe use of a nullable reference type, so you're done with this class.

Beheben von NULL-Werten führt zu ÄnderungenFixing nulls causes change

In vielen Fällen führt das Beheben einer Reihe von Warnungen in zugehörigem Code zu neuen Warnungen.Frequently, the fix for one set of warnings creates new warnings in related code. Sehen wir uns die Warnungen in Aktion durch Beheben der index.cshtml.cs-Klasse an.Let's see the warnings in action by fixing the index.cshtml.cs class. Öffnen Sie die Datei index.cshtml.cs, und überprüfen Sie den Code.Open the index.cshtml.cs file and examine the code. Diese Datei enthält den Code für die Indexseite: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;
                });
            }
        }
    }
}

Fügen Sie die #nullable enable-Anweisung hinzu, und Sie sehen zwei Warnungen.Add the #nullable enable directive and you'll see two warnings. Weder die ErrorText-Eigenschaft noch die NewsItems-Eigenschaft ist initialisiert.Neither the ErrorText property nor the NewsItems property is initialized. Bei einer Untersuchung dieser Klasse würden Sie zu dem Schluss kommen, dass beide Eigenschaften Nullwerte zulassende Verweistypen sein sollten: Beide haben private Setter.An examination of this class would lead you to believe that both properties should be nullable reference types: Both have private setters. Genau einer wird in der OnGet-Methode zugewiesen.Exactly one is assigned in the OnGet method. Bevor Sie Änderungen vornehmen, betrachten Sie die Benutzer beider Eigenschaften.Before making changes, look at the consumers of both properties. Auf der Seite selbst wird ErrorText vor dem Generieren von Markups für Fehler auf NULL überprüft.In the page itself, the ErrorText is checked against null before generating markup for any errors. Die NewsItems-Sammlung wird auf null überprüft, und um sicherzustellen, dass die Sammlung Elemente enthält.The NewsItems collection is checked against null, and checked to ensure the collection has items. Eine schnelle Lösung wäre, beide Eigenschaften zu Nullwerte zulassenden Verweistypen zu machen.A quick fix would be to make both properties nullable reference types. Eine bessere Lösung wäre, die Sammlung eines Nullwerte nicht zulassenden Verweistyps zu erstellen und beim Abrufen von Nachrichten der vorhandenen Sammlung Elemente hinzuzufügen.A better fix would be to make the collection a nonnullable reference type, and add items to the existing collection when retrieving news. Die erste Lösung ist, ? dem string-Typ für den ErrorText hinzuzufügen:The first fix is to add the ? to the string type for the ErrorText:

public string? ErrorText { get; private set; }

Diese Änderung würde anderen Code nicht beeinflussen, da jeder Zugriff auf die ErrorText-Eigenschaft bereits durch NULL-Überprüfungen geschützt wurde.That change won't ripple through other code, because any access to the ErrorText property was already guarded by null checks. Initialisieren Sie als Nächstes die NewsItems-Liste, und entfernen Sie den Eigenschaftensetter, und machen Sie ihn zu einer schreibgeschützten Eigenschaft:Next, initialize the NewsItems list and remove the property setter, making it a readonly property:

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

Damit wird die Warnung behoben, jedoch ein Fehler eingeführt.That fixed the warning but introduced an error. Die NewsItems-Liste ist nun korrigiert nach Erstellung, aber der Code, der die Liste in OnGet festlegt, muss der neuen API entsprechend geändert werden.The NewsItems list is now correct by construction, but the code that sets the list in OnGet must change to match the new API. Rufen Sie anstelle einer Zuweisung AddRange auf, um die Nachrichtenelemente der vorhandenen Liste hinzuzufügen:Instead of an assignment, call AddRange to add the news items to the existing list:

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

AddRange anstelle einer Zuordnung zu verwenden bedeutet, dass die GetNews-Methode IEnumerable anstelle einer List zurückgeben kann.Using AddRange instead of an assignment means that the GetNews method can return an IEnumerable instead of a List. Das spart eine Zuordnung.That saves one allocation. Ändern Sie die Signatur der Methode, und entfernen Sie den ToList-Aufruf, wie im folgenden Codebeispiel gezeigt: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);
}

Ändern der Signatur unterbricht auch einen der Tests.Changing the signature breaks one of tests as well. Öffnen Sie die NewsServiceTests.cs-Datei im Services-Ordner des SimpleFeedReader.Tests-Projekts.Open the NewsServiceTests.cs file in the Services folder of the SimpleFeedReader.Tests project. Navigieren Sie zum Returns_News_Stories_Given_Valid_Uri-Test, und ändern Sie den Typ der result-Variablen in IEnumerable<NewsItem>.Navigate to the Returns_News_Stories_Given_Valid_Uri test and change the type of the result variable to IEnumerable<NewsItem>. Ändern des Typs bedeutet, dass die Count-Eigenschaft nicht mehr verfügbar ist, also ersetzen Sie die Count-Eigenschaft in Assert mit einem Aufruf von 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());

Sie müssen ebenfalls eine using System.Linq-Anweisung am Anfang der Datei hinzufügen.You'll need to add a using System.Linq statement to the beginning of the file as well.

Dieser Satz von Änderungen hebt die besondere Berücksichtigung bei der Aktualisierung von Code hervor, der generische Instanziierungen enthält.This set of changes highlights special consideration when updating code that includes generic instantiations. Die Liste und die Elemente in der Liste sind nicht NULL-Werte zulassende Typen.Both the list and the elements in the list of non-nullable types. Die einen oder anderen oder beide könnten NULL-Werte zulassende Typen sein.Either or both could be nullable types. Alle folgenden Deklarationen sind zulässig:All the following declarations are allowed:

  • List<NewsStoryViewModel>: Nullwerte nicht zulassende Liste Nullwerte nicht zulassender Ansichtsmodelle.List<NewsStoryViewModel>: nonnullable list of nonullable view models.
  • List<NewsStoryViewModel?>: Nullwerte nicht zulassende Liste Nullwerte zulassender Ansichtsmodelle.List<NewsStoryViewModel?>: nonnullable list of nullable view models.
  • List<NewsStoryViewModel>?: Nullwerte zulassende Liste Nullwerte nicht zulassender Ansichtsmodelle.List<NewsStoryViewModel>?: nullable list of nonnullable view models.
  • List<NewsStoryViewModel?>?: Nullwerte zulassende Liste Nullwerte zulassender Ansichtsmodelle.List<NewsStoryViewModel?>?: nullable list of nullable view models.

Schnittstellen mit externem CodeInterfaces with external code

Da Sie Änderungen an der NewsService-Klasse vorgenommen haben, aktivieren Sie die #nullable enable-Anmerkung für diese Klasse.You've made changes to the NewsService class, so turn on the #nullable enable annotation for that class. Dadurch werden keine neuen Warnungen generiert.This won't generate any new warnings. Eine sorgfältige Prüfung der Klasse könnte jedoch die Veranschaulichung einiger Einschränkungen der Flussanalyse des Compilers erleichtern.However, careful examination of the class helps to illustrate some of the limitations of the compiler's flow analysis. Untersuchen Sie den Konstruktor:Examine the constructor:

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

Der IMapper-Parameter ist als Nullwerte nicht zulassender Verweis typisiert.The IMapper parameter is typed as a nonnullable reference. Er wird vom ASP.NET Core-Infrastrukturcode aufgerufen, sodass der Compiler nicht wirklich weiß, dass der IMapper niemals NULL sein wird.It's called by ASP.NET Core infrastructure code, so the compiler doesn't really know that the IMapper will never be null. Der standardmäßige ASP.NET Core-Abhängigkeitsinjektionscontainer (DI) löst eine Ausnahme aus, wenn er einen notwendigen Dienst nicht auflösen kann, damit der Code korrekt ist.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. Der Compiler kann nicht alle Aufrufe Ihrer öffentlichen APIs überprüfen, auch wenn der Code mit NULL-Werte zulassenden Anmerkungskontexten kompiliert wird.The compiler can't validate all calls to your public APIs, even if your code is compiled with nullable annotation contexts enabled. Darüber hinaus können Ihre Bibliotheken von Projekten genutzt werden, für die die Nutzung NULL-Werte zulassender Verweistypen noch nicht festgelegt ist.Furthermore, your libraries may be consumed by projects that have not yet opted into using nullable reference types. Überprüfen Sie die Eingaben in öffentliche APIs, obwohl Sie sie als Nullwerte nicht zulassende Typen deklariert haben.Validate inputs to public APIs even though you've declared them as nonnullable types.

Abrufen des CodesGet the code

Da Sie die Warnungen behoben haben, die Sie in der ersten Testkompilierung identifizierten, können Sie jetzt den NULL-Werte zulassenden Anmerkungskontext für beide Projekte aktivieren.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. Erstellen Sie die Projekte neu; der Compiler gibt keine Warnungen aus.Rebuild the projects; the compiler reports no warnings. Den Code für das fertige Projekt können Sie im GitHub-Repository dotnet/samples aufrufen.You can get the code for the finished project in the dotnet/samples GitHub repository.

Die neuen Features, die NULL-Werte zulassende Verweistypen unterstützen, helfen Ihnen, mögliche Fehler in der Behandlung von null-Werten in Ihrem Code zu suchen und zu beheben.The new features that support nullable reference types help you find and fix potential errors in how you handle null values in your code. Das Aktivieren des NULL-Werte zulassenden Anmerkungskontexts ermöglicht Ihnen, Ihre Entwurfsabsicht auszudrücken: Einige Variablen sollten niemals NULL sein, andere Variablen können NULL-Werte enthalten.Enabling the nullable annotation context allows you to express your design intent: some variables should never be null, other variables may contain null values. Diese Funktionen erleichtern Ihnen, Ihre Entwurfsabsicht zu deklarieren.These features make it easier for you to declare your design intent. Auf ähnliche Weise weist der NULL-Werte zulassende Warnungskontext den Compiler an, Warnungen auszugeben, wenn Sie diese Absicht verletzt haben.Similarly, the nullable warning context instructs the compiler to issue warnings when you have violated that intent. Diese Warnungen leiten Sie an, Aktualisierungen vorzunehmen, die Ihren Code robuster machen, sodass das Auslösen einer NullReferenceException während der Ausführung unwahrscheinlicher wird.Those warnings guide you to make updates that make your code more resilient and less likely to throw a NullReferenceException during execution. Sie können den Rahmen dieser Kontexte steuern, damit Sie sich auf lokale zu migrierende Codebereiche konzentrieren können, während die übrige Codebasis hiervon unberührt bleibt.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. In der Praxis können Sie diese Migrationsaufgabe als Teil der regelmäßigen Wartung Ihrer Klassen durchführen.In practice, you can make this migration task a part of regular maintenance to your classes. Dieses Tutorial veranschaulicht das Verfahren zum Migrieren einer Anwendung zur Verwendung von NULL-Werte zulassenden Verweistypen.This tutorial demonstrated the process to migrate an application to use nullable reference types. Der PR von Jon Skeet zum Integrieren Nullwerte zulassender Verweistypen in NodaTime bietet Ihnen ein umfangreicheren Beispiel dieses Prozesses aus der realen Welt.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.