Icke-bakåtkompatibla ändringar

Det är viktigt att ett .NET-bibliotek hittar en balans mellan stabilitet för befintliga användare och innovation för framtiden. Biblioteksförfattare lutar sig mot att omstrukturera och ompröva kod tills den är perfekt, men att bryta befintliga användare har en negativ inverkan, särskilt för bibliotek på låg nivå.

Projekttyper och icke-bakåtkompatibla ändringar

Hur ett bibliotek används av .NET-communityn ändrar effekten av icke-bakåtkompatibla ändringar för slutanvändare.

  • Låg- och mellannivåbibliotek som serialiserare, HTML-parser, databasobjektrelationsmappning eller webbramverk påverkas mest av icke-bakåtkompatibla ändringar.

    Byggblockspaket används av slutanvändare för att skapa program och av andra bibliotek som NuGet-beroenden. Du skapar till exempel ett program och använder en klient med öppen källkod för att anropa en webbtjänst. En icke-bakåtkompatibel uppdatering av ett beroende som klienten använder är inte något du kan åtgärda. Det är klienten med öppen källkod som behöver ändras och du har ingen kontroll över den. Du måste hitta kompatibla versioner av biblioteken eller skicka en korrigering till klientbiblioteket och vänta på en ny version. Det värsta är om du vill använda två bibliotek som är beroende av ömsesidigt inkompatibla versioner av ett tredje bibliotek.

  • Bibliotek på hög nivå , till exempel en uppsättning användargränssnittskontroller, är mindre känsliga för icke-bakåtkompatibla ändringar.

    Bibliotek på hög nivå refereras direkt i ett slutanvändarprogram. Om icke-bakåtkompatibla ändringar inträffar kan utvecklaren välja att uppdatera till den senaste versionen eller ändra programmet så att det fungerar med den icke-bakåtkompatibla ändringen.

✔️ Tänk på hur biblioteket ska användas. Vilken effekt kommer icke-bakåtkompatibla ändringar att ha på program och bibliotek som använder den?

✔️ Minimera icke-bakåtkompatibla ändringar när du utvecklar ett .NET-bibliotek på låg nivå.

✔️ ÖVERVÄG att publicera en större omskrivning av ett bibliotek som ett nytt NuGet-paket.

Typer av icke-bakåtkompatibla ändringar

Icke-bakåtkompatibla ändringar delas in i olika kategorier och påverkas inte lika mycket.

Ändring av icke-bakåtkompatibel källa

En källbrytande ändring påverkar inte programkörningen, men orsakar kompileringsfel nästa gång programmet kompileras om. En ny överlagring kan till exempel skapa en tvetydighet i metodanrop som var tvetydiga tidigare, eller så bryter en omdöpt parameter anropare som använder namngivna parametrar.

public class Task
{
    // Adding a type called Task could conflict with System.Threading.Tasks.Task at compilation
}

Eftersom en källbrytande ändring bara är skadlig när utvecklare kompilera om sina program är det den minst störande icke-bakåtkompatibla ändringen. Utvecklare kan enkelt åtgärda sin egen brutna källkod.

Beteendebrytande ändring

Beteendeändringar är den vanligaste typen av icke-bakåtkompatibla ändringar: nästan alla ändringar i beteendet kan orsaka ett logikfel för en konsument. Ändringar i biblioteket, till exempel metodsignaturer, undantag som genereras eller indataformat eller utdataformat, kan påverka bibliotekskonsumenterna negativt. Även en felkorrigering kan betraktas som en icke-bakåtkompatibel ändring om användarna förlitade sig på det tidigare brutna beteendet.

Att lägga till funktioner och förbättra dåliga beteenden är bra, men utan att bry sig kan det göra det mycket svårt för befintliga användare att uppgradera. En metod för att hjälpa utvecklare att hantera beteendebrytande ändringar är att dölja dem bakom inställningarna. Inställningar låta utvecklare uppdatera till den senaste versionen av biblioteket samtidigt som de väljer att anmäla sig eller välja bort icke-bakåtkompatibla ändringar. Med den här strategin kan utvecklare hålla sig uppdaterade samtidigt som de kan anpassa sin förbrukande kod över tid.

Till exempel har ASP.NET Core MVC begreppet kompatibilitetsversion som ändrar funktionerna som är aktiverade och inaktiverade på MvcOptions.

✔️ ÖVERVÄG att lämna nya funktioner inaktiverade som standard, om de påverkar befintliga användare, och låt utvecklare välja att använda funktionen med en inställning.

Mer information om beteendebrytande ändringar i .NET-API:er finns i .NET-beteendeändringarnas kompatibilitet.

Binär icke-bakåtkompatibel ändring

En binär icke-bakåtkompatibel ändring sker när du ändrar det offentliga API:et för biblioteket, så sammansättningar som kompilerats mot äldre versioner av biblioteket kan inte längre anropa API:et. Om du till exempel ändrar en metods signatur genom att lägga till en ny parameter kommer sammansättningar som kompilerats mot den äldre versionen av biblioteket att generera en MissingMethodException.

En binär icke-bakåtkompatibel ändring kan också bryta en hel sammansättning. Om du byter namn på en sammansättning med AssemblyName ändras sammansättningens identitet, liksom att lägga till, ta bort eller ändra sammansättningens starka namngivningsnyckel. En ändring av en sammansättnings identitet bryter all kompilerad kod som använder den.

❌ Ändra INTE ett sammansättningsnamn.

❌ Lägg INTE till, ta bort eller ändra den starka namngivningsnyckeln.

✔️ ÖVERVÄG att använda abstrakta basklasser i stället för gränssnitt.

Om du lägger till något i ett gränssnitt misslyckas befintliga typer som implementerar det. Med en abstrakt basklass kan du lägga till en virtuell standardimplementering.

✔️ ÖVERVÄG att placera på de ObsoleteAttribute typer och medlemmar som du tänker ta bort. Attributet bör ha instruktioner för att uppdatera kod för att inte längre använda det föråldrade API:et.

Kod som anropar typer och metoder med ObsoleteAttribute genererar en byggvarning med meddelandet som skickas till attributet. Varningarna ger personer som använder den föråldrade API-ytan tid att migrera så att när det föråldrade API:et tas bort använder de flesta inte längre det.

public class Document
{
    [Obsolete("LoadDocument(string) is obsolete. Use LoadDocument(Uri) instead.")]
    public static Document LoadDocument(string uri)
    {
        return LoadDocument(new Uri(uri));
    }

    public static Document LoadDocument(Uri uri)
    {
        // Load the document
    }
}

✔️ ÖVERVÄG att behålla typer och metoder på ObsoleteAttribute obestämd tid i bibliotek på låg och mellannivå.

Att ta bort API:er är en binär icke-bakåtkompatibel ändring. Att överväga att behålla föråldrade typer och metoder om underhåll av dem är låg kostnad och lägger inte till mycket teknisk skuld till ditt bibliotek. Om du inte tar bort typer och metoder kan du undvika de värsta scenarier som nämns ovan.

Mer information om vilka .NET API-ändringar som bryter binär kompatibilitet finns i kompatibilitet med offentliga .NET-kontrakt.

Se även