Strategieën voor null-migratie

Tip

Een nieuw project starten? Nieuwe projecten die zijn gemaakt op basis van .NET 6 of hoger, hebben al <Nullable>enable</Nullable> ingesteld. U hebt geen migratiestrategie nodig: ga meteen naar nullable-waarschuwingen oplossen.

Een bestaande codebase onderhouden? Lees nullable-verwijzingstypen eerst om contexten, annotaties en de null-status te begrijpen. In dit artikel wordt ervan uitgegaan dat u bekend bent met deze concepten en klaar bent om een implementatie te plannen.

Wanneer u null-referentietypen inschakelt voor een groot project dat is gestart voordat nullable-referentietypen werden geïntroduceerd, produceert de compiler veel waarschuwingen tegelijk. Migratie gaat over het sequentiëren van het werk: het kiezen van een standaardcontext, het weergeven van waarschuwingen per bestand of sectie per sectie en het samenvoegen <Nullable>enable</Nullable> van het hele project. De juiste volgorde is afhankelijk van hoe actief de codebase is en hoeveel risico u in één pas kunt nemen.

De eindstatus is in elk geval hetzelfde: de projectsets <Nullable>enable</Nullable> en bevat geen #nullable preprocessorrichtlijnen.

Een standaardcontext kiezen

De null-context heeft twee onafhankelijke vlaggen: aantekeningen (of ? een null-referentietype declareert) en waarschuwingen (of de compiler diagnostische gegevens verzendt). Stel ze samen als één <Nullable> waarde in:

Standaardwaarde Annotations Warnings Ideaal voor
disable (impliciet) uit uit Stabiele bibliotheken waarvoor in deze ronde geen werk aan nieuwe functies wordt gedaan.
enable on on Actieve codebases met frequente nieuwe bestanden. Nieuwe code is standaard ingeschakeld.
warnings uit on Migratie in twee fasen: pak eerst de waarschuwingen aan, annoteer later.
annotations on uit Aantekeningen toevoegen aan de openbare API voordat u de interne waarschuwingen kunt oplossen.

Kies de strategie die het beste overeenkomt met de doelstellingen voor uw projectmigratie:

  • Schakel deze functie uit als de standaardinstelling. Stel <Nullable>disable</Nullable> in en voeg #nullable enable bovenaan elk bestand toe wanneer u het migreert. Bestaande bestanden blijven null-vergetelbaar totdat u ze aanraakt. Deze optie heeft de laagste wrijving voor stabiele bibliotheken, omdat er zelden nieuwe functies werken.
  • Inschakelen als de standaardwaarde. Stel <Nullable>enable</Nullable> in en voeg #nullable disable bovenaan toe aan elk bestand dat u nog niet hebt gemigreerd. Elk nieuw bestand is vanaf het begin null-aware, zodat de migratieachterstand alleen kan worden verkleind. Deze keuze is beter wanneer ontwikkeling actief is.
  • Waarschuwingen als de standaardinstelling. Stel <Nullable>warnings</Nullable>in. Kies deze standaardinstelling voor een migratie met twee fasen: adreswaarschuwingen terwijl elk verwijzingstype nog steeds wordt behandeld als vergetelheid en schakel aantekeningen in. De splitsing in twee fasen zorgt dat de diff van elke stap gericht blijft.
  • Annotaties als standaard. Stel <Nullable>annotations</Nullable>in. Begin met het annoteren van uw openbare API (? op leden die null kunnen hebben) voordat u zich op waarschuwingen stort. De compiler verzendt nog geen waarschuwingen, zodat u het API-oppervlak kunt vereffenen zonder afleiding.

Het projectbestand bepaalt de algemene standaardwaarde. #nullable preprocessor-instructies overschrijven deze standaardwaarde voor een codegebied:

<PropertyGroup>
  <Nullable>enable</Nullable>
</PropertyGroup>

Binnen bronbestanden kiest de richtlijn een regio in of uit de null-instelling van het project:

#nullable disable
public static class LegacyHelper
{
    // This file is nullable-oblivious. Reference types use the legacy rules.
    public static string GetGreeting(string name) =>
        name == null ? "hello" : $"hello {name}";
}
#nullable restore

#nullable enable
public static class MigratedHelper
{
    // This file is fully migrated. Reference types are non-nullable by default.
    public static string GetGreeting(string? name) =>
        name is null ? "hello" : $"hello {name}";
}
#nullable restore

Bestand per bestand migreren

De meest voorspelbare manier om een groot project te migreren, is door waarschuwingen of aantekeningen per bestand in te schakelen. Het patroon is hetzelfde, ongeacht de standaardinstelling die u kiest:

  1. Kies een bestand. Begin met de diepste bladtypen in uw afhankelijkheidsgrafiek en ga vervolgens naar buiten. Het annoteren van een type leidt tot nieuwe waarschuwingen in de code die het aanroept, dus door van onderaf te werken minimaliseert u herwerk.
  2. Voeg de #nullable-instructie toe om het bestand het nieuwe gedrag te laten gebruiken. Gebruik #nullable enable deze optie als u beide vlaggen wilt. Gebruiken #nullable enable warnings voor alleen waarschuwingen.
  3. Los de waarschuwingen in het bestand op met behulp van de technieken in Nullable-waarschuwingen oplossen.
  4. Herhaal dit voor het volgende bestand.
  5. Wanneer elk bestand in het project een eigen instructie heeft, verwijdert u de instructies en stelt u <Nullable>enable</Nullable> in op projectniveau.

Als uw codebase al heeft <Nullable>enable</Nullable>, rijdt u de tegenovergestelde richting. Onderdrukt waarschuwingen in niet-gemigreerde bestanden totdat u klaar bent. Gebruik #nullable disable om bestanden uit te sluiten en verwijder vervolgens de onderdrukkingen één voor één.

Migreren in twee fasen

Een migratie in twee fasen scheidt de twee soorten werkzaamheden die nullable referentietypen met zich meebrengen. U kunt de fasen in beide richtingen rangordenen, afhankelijk van welke vorm van stabiliteit voor u belangrijk is.

Waarschuwingen eerst en vervolgens aantekeningen

Begin met waarschuwingen wanneer het oplossen van latente System.NullReferenceException bugs prioriteit heeft:

  1. Fase 1: Adreswaarschuwingen. Stel de standaardinstelling voor het project in op warnings. Referentietypen blijven null-vergetelbaar, dus het typesysteem verandert nog niet. De compiler geeft waarschuwingen op alle plaatsen waar uw bestaande code mogelijk al een System.NullReferenceException veroorzaakt. Voeg null-controles toe, herstructureer de codeflow of pas attributen toe totdat het project vrij van waarschuwingen is. Elke oplossing maakt de productiecode toleranter, zelfs voordat aantekeningen bestaan.
  2. Fase 2: Aantekeningen toevoegen. Zet de standaardinstelling van het project op enable. Referentietypen zijn nu standaard niet-nullbaar en var lokale variabelen worden nullbaar. Nieuwe waarschuwingen geven declaraties weer die niet overeenkomen met de manier waarop de variabelen worden gebruikt. Voeg ? toe aan typen die null moeten toestaan. Maak API’s die waarden vereisen die niet null zijn strenger.

Aantekeningen eerst en vervolgens waarschuwingen

Kies eerst voor annotaties als het stabiliseren van de publieke API prioriteit heeft. Deze volgorde is geschikt voor bibliotheken: u kunt geannoteerde signaturen leveren, zodat gebruikers de juiste contracten zien, en vervolgens de interne waarschuwingen volgens uw eigen planning afhandelen.

  1. Fase 1: Aantekeningen toevoegen. Stel de standaardinstelling voor het project in op annotations. Verwijzingstypen zijn standaard niet-nullable, maar de compiler geeft geen waarschuwingen, zodat u daar geen last van hebt. Doorloop de openbare API en voeg ? toe aan elk element dat op legitieme wijze null kan retourneren of accepteren. Draai de ondertekeningen aan die dat niet zouden moeten. Omdat waarschuwingen zijn uitgeschakeld, kunt u de vorm van de API in gerichte commits vastleggen zonder dat u tegelijkertijd ook de implementatie hoeft uit te pluizen.
  2. Fase 2: Adreswaarschuwingen. Zet de standaardinstelling van het project op enable. De annotaties die u in fase 1 hebt toegevoegd, voeden nu de null-state-analyse, zodat de waarschuwingen die de compiler genereert vanaf het begin van hogere kwaliteit zijn: elke waarschuwing wijst op code waarvan het gedrag niet overeenkomt met het contract dat u al hebt gepubliceerd. Los deze op met de technieken in Waarschuwingen over null-waarden oplossen.

Kiezen tussen de volgordes

Elke volgorde scheidt de fasen in kleinere, meer controleerbare verschillen. De ene fase verandert alleen gedrag en de andere wijzigingen alleen typen. Het nadeel is dat u elk bestand twee keer bezoekt. Voor volwassen, stabiele code waarbij elke wijziging risico loopt, zijn de twee passen meestal de moeite waard. Kies eerst waarschuwingen als u actieve code beter wilt beveiligen. Kies eerst aantekeningen wanneer u het meest een stabiel contract wilt publiceren.

Gegenereerde code wordt uitgesloten

De compiler behandelt bestanden die zijn gemarkeerd als gegenereerd alsof de null-context is uitgeschakeld, ongeacht de instelling van het project. Een bestand wordt als gegenereerd beschouwd wanneer aan een van de volgende voorwaarden wordt voldaan:

  • Een .editorconfig-regel stelt generated_code = true in voor het bestand.
  • De eerste opmerking in het bestand bevat <auto-generated> of <auto-generated/>.
  • De bestandsnaam begint met TemporaryGeneratedFile_.
  • De bestandsnaam eindigt op .designer.cs, .generated.csof .g.cs.g.i.cs.

Generatoren die uitvoer produceren die rekening houdt met null-waarden, kunnen zich hiervoor opnieuw inschakelen door #nullable enable bovenaan in het gegenereerde bestand op te nemen.

Wanneer u klaar bent

Nadat elk bestand deelneemt aan de standaardinstelling van het project en het <Nullable>enable</Nullable> element is ingesteld:

  • Verwijder elke #nullable instructie in uw bron.
  • Verwijder de initialisaties null! en default! die u alleen hebt toegevoegd om waarschuwingen tijdens de migratie te onderdrukken. Vervang ze door een correcte initialisatie, of maak het type een nullable referentietype.
  • Controleer de openbare API steekproefsgewijs. Elk lid dat retourneert of accepteertnull, moet worden voorzien van aantekeningen.? De aantekeningen maken deel uit van uw contract zodra het pakket wordt verzonden.

U hebt nu dezelfde status als nieuwe projecten: nullable-referentietypen maken deel uit van het typesysteem en eventuele nieuwe waarschuwingen weerspiegelen een echte niet-overeenkomst tussen declaraties en code. Gebruik Nullable-waarschuwingen oplossen om ze aan te pakken zodra ze optreden.