Versionshantering i C#

I den här självstudien får du lära dig vad versionshantering innebär i .NET. Du lär dig också vilka faktorer du bör tänka på när du versionshanterar ditt bibliotek och uppgraderar till en ny version av ett bibliotek.

Redigeringsbibliotek

Som utvecklare som har skapat .NET-bibliotek för offentligt bruk har du förmodligen varit i situationer där du måste distribuera nya uppdateringar. Hur du går till väga för den här processen är viktigt eftersom du behöver se till att det sker en sömlös övergång av befintlig kod till den nya versionen av biblioteket. Här är flera saker att tänka på när du skapar en ny version:

Semantisk versionshantering

Semantisk versionshantering (SemVer för kort) är en namngivningskonvention som tillämpas på versioner av ditt bibliotek för att beteckna specifika milstolpehändelser. Helst bör versionsinformationen som du ger ditt bibliotek hjälpa utvecklare att fastställa kompatibiliteten med sina projekt som använder äldre versioner av samma bibliotek.

Den mest grundläggande metoden för SemVer är 3-komponentformatet MAJOR.MINOR.PATCH, där:

  • MAJOR ökas när du gör inkompatibla API-ändringar
  • MINOR ökas när du lägger till funktioner på ett bakåtkompatibelt sätt
  • PATCH ökas när du gör bakåtkompatibla felkorrigeringar

Det finns också sätt att ange andra scenarier, till exempel förhandsversioner, när du tillämpar versionsinformation på .NET-biblioteket.

Bakåtkompatibilitet

När du släpper nya versioner av biblioteket är bakåtkompatibilitet med tidigare versioner förmodligen ett av de viktigaste problemen. En ny version av biblioteket är källkompatibel med en tidigare version om kod som är beroende av den tidigare versionen kan, när den kompileras om, fungera med den nya versionen. En ny version av biblioteket är binärkompatibel om ett program som är beroende av den gamla versionen, utan omkompilering, kan arbeta med den nya versionen.

Här följer några saker att tänka på när du försöker upprätthålla bakåtkompatibilitet med äldre versioner av biblioteket:

  • Virtuella metoder: När du gör en virtuell metod icke-virtuell i din nya version innebär det att projekt som åsidosätter den metoden måste uppdateras. Detta är en enorm icke-bakåtkompatibel förändring och är starkt modfälld.
  • Metodsignaturer: När du uppdaterar ett metodbeteende måste du också ändra dess signatur, du bör i stället skapa en överlagring så att kodanrop till den metoden fortfarande fungerar. Du kan alltid ändra den gamla metodsignaturen för att anropa den nya metodsignaturen så att implementeringen förblir konsekvent.
  • Föråldrat attribut: Du kan använda det här attributet i koden för att ange klasser eller klassmedlemmar som är inaktuella och som sannolikt kommer att tas bort i framtida versioner. Detta säkerställer att utvecklare som använder ditt bibliotek är bättre förberedda för icke-bakåtkompatibla ändringar.
  • Valfria metodargument: När du gör tidigare valfria metodargument obligatoriska eller ändrar deras standardvärde måste all kod som inte anger dessa argument uppdateras.

Kommentar

Att göra obligatoriska argument valfria bör ha mycket liten effekt, särskilt om det inte ändrar metodens beteende.

Ju enklare du gör det för användarna att uppgradera till den nya versionen av biblioteket, desto mer troligt är det att de uppgraderar tidigare.

Konfigurationsfil för program

Som .NET-utvecklare finns det en mycket stor chans att du har stött på app.config filen som finns i de flesta projekttyper. Den här enkla konfigurationsfilen kan gå långt för att förbättra distributionen av nya uppdateringar. Du bör vanligtvis utforma dina bibliotek på ett sådant sätt att information som sannolikt kommer att ändras regelbundet lagras i app.config filen, på det här sättet när sådan information uppdateras, behöver konfigurationsfilen för äldre versioner bara ersättas med den nya utan att biblioteket behöver kompileras om.

Använda bibliotek

Som utvecklare som använder .NET-bibliotek som skapats av andra utvecklare är du förmodligen medveten om att en ny version av ett bibliotek kanske inte är helt kompatibel med ditt projekt och du kanske ofta måste uppdatera koden för att arbeta med dessa ändringar.

Som tur är har C# och .NET-ekosystemet funktioner och tekniker som gör att vi enkelt kan uppdatera appen så att den fungerar med nya versioner av bibliotek som kan medföra icke-bakåtkompatibla ändringar.

Omdirigering av sammansättningsbindning

Du kan använda filen app.config för att uppdatera versionen av ett bibliotek som appen använder. Genom att lägga till vad som kallas en bindningsomdirigering kan du använda den nya biblioteksversionen utan att behöva kompilera om din app. I följande exempel visas hur du uppdaterar appens app.config-fil för att använda 1.0.1 korrigeringsversionen ReferencedLibrary i stället för den version som den 1.0.0 ursprungligen kompilerades med.

<dependentAssembly>
    <assemblyIdentity name="ReferencedLibrary" publicKeyToken="32ab4ba45e0a69a1" culture="en-us" />
    <bindingRedirect oldVersion="1.0.0" newVersion="1.0.1" />
</dependentAssembly>

Kommentar

Den här metoden fungerar bara om den nya versionen av ReferencedLibrary är binärkompatibel med din app. Se avsnittet Bakåtkompatibilitet ovan för ändringar att hålla utkik efter när du fastställer kompatibilitet.

Ny…

Du använder new modifieraren för att dölja ärvda medlemmar i en basklass. Det här är ett sätt som härledda klasser kan svara på uppdateringar i basklasser.

Se följande exempel:

public class BaseClass
{
    public void MyMethod()
    {
        Console.WriteLine("A base method");
    }
}

public class DerivedClass : BaseClass
{
    public new void MyMethod()
    {
        Console.WriteLine("A derived method");
    }
}

public static void Main()
{
    BaseClass b = new BaseClass();
    DerivedClass d = new DerivedClass();

    b.MyMethod();
    d.MyMethod();
}

Output

A base method
A derived method

I exemplet ovan kan du se hur DerivedClass döljer metoden MyMethod som finns i BaseClass. Det innebär att när en basklass i den nya versionen av ett bibliotek lägger till en medlem som redan finns i din härledda klass kan du helt enkelt använda new modifieraren på din härledda klassmedlem för att dölja basklassmedlemmen.

När ingen new modifierare har angetts döljer en härledd klass som standard motstridiga medlemmar i en basklass, även om en kompilatorvarning genereras kommer koden fortfarande att kompileras. Det innebär att om du bara lägger till nya medlemmar i en befintlig klass blir den nya versionen av biblioteket både käll- och binärkompatibel med kod som är beroende av den.

Åsidosätta

Modifieraren override innebär att en härledd implementering utökar implementeringen av en basklassmedlem i stället för att dölja den. Basklassmedlemmen måste ha virtual modifieraren tillämpad på den.

public class MyBaseClass
{
    public virtual string MethodOne()
    {
        return "Method One";
    }
}

public class MyDerivedClass : MyBaseClass
{
    public override string MethodOne()
    {
        return "Derived Method One";
    }
}

public static void Main()
{
    MyBaseClass b = new MyBaseClass();
    MyDerivedClass d = new MyDerivedClass();

    Console.WriteLine("Base Method One: {0}", b.MethodOne());
    Console.WriteLine("Derived Method One: {0}", d.MethodOne());
}

Output

Base Method One: Method One
Derived Method One: Derived Method One

Modifieraren override utvärderas vid kompileringstillfället och kompilatorn utlöser ett fel om den inte hittar någon virtuell medlem att åsidosätta.

Dina kunskaper om de diskuterade teknikerna och din förståelse för de situationer där du kan använda dem kommer att underlätta övergången mellan versioner av ett bibliotek.