Przechowywanie wersji w języku C#

W tym samouczku dowiesz się, co oznacza przechowywanie wersji na platformie .NET. Poznasz również czynniki, które należy wziąć pod uwagę podczas przechowywania wersji biblioteki, a także uaktualniania do nowej wersji biblioteki.

Biblioteki tworzenia

Jako deweloper, który utworzył biblioteki .NET do użytku publicznego, najprawdopodobniej w sytuacjach, w których trzeba wdrożyć nowe aktualizacje. Sposób wykonywania tego procesu ma wiele znaczenia, ponieważ musisz mieć pewność, że istnieje bezproblemowe przejście istniejącego kodu do nowej wersji biblioteki. Poniżej przedstawiono kilka kwestii, które należy wziąć pod uwagę podczas tworzenia nowej wersji:

Semantyczne przechowywanie wersji

Semantyczne przechowywanie wersji (SemVer for short) to konwencja nazewnictwa stosowana do wersji biblioteki w celu oznaczenia określonych zdarzeń punktowych. W idealnym przypadku informacje o wersji udostępniane biblioteki powinny ułatwić deweloperom określenie zgodności ze swoimi projektami korzystającymi ze starszych wersji tej samej biblioteki.

Najbardziej podstawowym podejściem do rozwiązania SemVer jest format MAJOR.MINOR.PATCHskładnika 3, gdzie:

  • MAJOR jest zwiększana w przypadku wprowadzania niezgodnych zmian interfejsu API
  • MINOR funkcja jest zwiększana w przypadku dodawania funkcji w sposób zgodny z poprzednimi wersjami
  • PATCH jest zwiększana w przypadku wprowadzania poprawek usterek zgodnych z poprzednimi wersjami

Istnieją również sposoby określania innych scenariuszy, na przykład wersji wstępnych, podczas stosowania informacji o wersji do biblioteki platformy .NET.

Zgodność z poprzednimi wersjami

W miarę wydawania nowych wersji biblioteki zgodność z poprzednimi wersjami będzie najprawdopodobniej jedną z głównych kwestii. Nowa wersja biblioteki jest zgodna ze źródłem z poprzednią wersją, jeśli kod zależny od poprzedniej wersji może po ponownym skompilować wersję, pracować z nową wersją. Nowa wersja biblioteki jest zgodna binarnie, jeśli aplikacja zależna od starej wersji może bez ponownej kompilacji pracować z nową wersją.

Poniżej przedstawiono kilka kwestii, które należy wziąć pod uwagę podczas próby zachowania zgodności z poprzednimi wersjami biblioteki:

  • Metody wirtualne: jeśli w nowej wersji zostanie utworzona metoda wirtualna, która nie jest wirtualna, oznacza to, że projekty, które zastępują tę metodę, będą musiały zostać zaktualizowane. Jest to ogromna zmiana powodująca niezgodność i jest zdecydowanie zniechęcona.
  • Sygnatury metod: podczas aktualizowania zachowania metody należy również zmienić jego podpis, należy utworzyć przeciążenie, aby kod wywołujący tę metodę nadal działał. Zawsze można manipulować starym podpisem metody w celu wywołania nowego podpisu metody, aby implementacja pozostała spójna.
  • Przestarzały atrybut: ten atrybut można użyć w kodzie, aby określić klasy lub składowe klasy, które są przestarzałe i prawdopodobnie zostaną usunięte w przyszłych wersjach. Dzięki temu deweloperzy korzystający z biblioteki są lepiej przygotowani do zmian powodujących niezgodność.
  • Opcjonalne argumenty metody: jeśli argumenty metody są wcześniej opcjonalne lub zmieniasz ich wartość domyślną, cały kod, który nie dostarcza tych argumentów, będzie musiał zostać zaktualizowany.

Uwaga

Wprowadzanie obowiązkowych argumentów opcjonalnych powinno mieć bardzo niewielki wpływ, zwłaszcza jeśli nie zmienia zachowania metody.

Im łatwiej jest umożliwić użytkownikom uaktualnienie do nowej wersji biblioteki, tym bardziej prawdopodobne jest, że będą one uaktualniać wcześniej.

Plik konfiguracji aplikacji

Jako deweloper platformy .NET istnieje bardzo duże prawdopodobieństwo wystąpienia app.config pliku w większości typów projektów. Ten prosty plik konfiguracji może przejść długą drogę do poprawy wdrażania nowych aktualizacji. Biblioteki powinny być zwykle projektowane w taki sposób, że informacje, które mogą być regularnie zmieniane, są przechowywane w app.config pliku, w ten sposób po zaktualizowaniu takich informacji plik konfiguracji starszych wersji musi zostać zastąpiony nowym, bez konieczności ponownego komplikowania biblioteki.

Korzystanie z bibliotek

Jako deweloper korzystający z bibliotek .NET utworzonych przez innych deweloperów najprawdopodobniej wiesz, że nowa wersja biblioteki może nie być w pełni zgodna z projektem i często może się okazać, że trzeba zaktualizować kod, aby pracować z tymi zmianami.

Szczęśliwe dla Ciebie język C# i ekosystem platformy .NET są wyposażone w funkcje i techniki, które pozwalają nam łatwo aktualizować naszą aplikację do pracy z nowymi wersjami bibliotek, które mogą wprowadzać zmiany powodujące niezgodność.

Przekierowanie powiązania zestawu

Możesz użyć pliku app.config , aby zaktualizować wersję biblioteki używanej przez aplikację. Dodając element nazywany przekierowaniem powiązania, możesz użyć nowej wersji biblioteki bez konieczności ponownego kompilowania aplikacji. W poniższym przykładzie pokazano, jak zaktualizować plik app.config aplikacji, aby użyć 1.0.1 wersji ReferencedLibrary poprawki zamiast wersji, z 1.0.0 którą została pierwotnie skompilowana.

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

Uwaga

Takie podejście będzie działać tylko wtedy, gdy nowa wersja programu ReferencedLibrary jest zgodna z twoją aplikacją. Zobacz sekcję Zgodność z poprzednimi wersjami powyżej, aby zapoznać się ze zmianami podczas określania zgodności.

Nowa…

Modyfikator służy new do ukrywania dziedziczych składowych klasy bazowej. Jest to jeden ze sposobów, w jaki klasy pochodne mogą reagować na aktualizacje w klasach bazowych.

Spójrz na następujący przykład:

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();
}

Wyjście

A base method
A derived method

W powyższym przykładzie widać, jak DerivedClass ukrywa metodę MyMethod w BaseClasspliku . Oznacza to, że gdy klasa bazowa w nowej wersji biblioteki dodaje składową, która już istnieje w klasie pochodnej, możesz po prostu użyć new modyfikatora w składowej klasy pochodnej, aby ukryć składową klasy bazowej.

Jeśli modyfikator nie new zostanie określony, klasa pochodna domyślnie ukrywa sprzeczne elementy członkowskie w klasie bazowej, chociaż zostanie wygenerowane ostrzeżenie kompilatora, kod będzie nadal kompilowany. Oznacza to, że po prostu dodanie nowych elementów członkowskich do istniejącej klasy sprawia, że nowa wersja biblioteki źródłowej i binarnej jest zgodna z kodem, który jest od niego zależny.

override

Modyfikator oznacza, że implementacja override pochodna rozszerza implementację składowej klasy bazowej, a nie ukrywa ją. Składowa klasy bazowej virtual musi mieć zastosowany modyfikator.

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());
}

Wyjście

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

override Modyfikator jest oceniany w czasie kompilacji, a kompilator zgłosi błąd, jeśli nie znajdzie wirtualnego elementu członkowskiego do zastąpienia.

Twoja wiedza na temat omówionych technik i zrozumienia sytuacji, w których można ich używać, będzie daleko w kierunku złagodzenia przejścia między wersjami biblioteki.