Udostępnij za pośrednictwem


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.

Wersja języka

Kompilator języka C# jest częścią zestawu .NET SDK. Domyślnie kompilator wybiera wersję języka C#zgodną z wybranym programem TFM dla projektu. Jeśli wersja zestawu SDK jest większa niż wybrana platforma, kompilator może użyć nowszej wersji językowej. Możesz zmienić wartość domyślną, ustawiając LangVersion element w projekcie. Możesz dowiedzieć się, jak w naszym artykule o opcjach kompilatora.

Ostrzeżenie

LangVersion Ustawienie elementu na latest wartość jest niezalecone. Ustawienie latest oznacza, że zainstalowany kompilator używa najnowszej wersji. Może to zmienić się z maszyny na maszynę, co sprawia, że kompilacje są zawodne. Ponadto włącza funkcje językowe, które mogą wymagać funkcji środowiska uruchomieniowego lub biblioteki, które nie są uwzględnione w bieżącym zestawie SDK.

Biblioteki autorskie

Jako deweloper, który utworzył biblioteki .NET do użytku publicznego, z pewnością byłeś 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 wersjonowanie

Wersjonowanie semantyczne (w skrócie SemVer) to konwencja nazewnictwa stosowana do wersji twojej biblioteki w celu oznaczenia określonych wydarzeń kamieni milowych. 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 SemVer jest 3-elementowy format MAJOR.MINOR.PATCH, gdzie:

  • MAJOR jest inkrementowana w przypadku wprowadzania niekompatybilnych zmian interfejsu API
  • MINOR jest zwiększany, gdy dodajesz funkcjonalność w sposób wstecznie kompatybilny
  • PATCH jest inkrementowane, gdy wprowadzane są poprawki usterek kompatybilnych wstecz

Istnieją również sposoby określania innych scenariuszy, na przykład wersji wstępnych, podczas stosowania informacji o wersjach do biblioteki .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 źródłowo z poprzednią wersją, jeśli kod zależny od poprzedniej wersji po ponownym skompilowaniu może działać 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 zdecydowanie się jej odradza.
  • Sygnatury metod: Gdy zaktualizowanie zachowania metody wymaga również zmiany jej sygnatury, zamiast tego powinieneś utworzyć jej 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 niekompatybilność.
  • Argumenty opcjonalne metody: kiedy wcześniej opcjonalne argumenty metody stają się obowiązkowe lub zmienia się ich wartość domyślna, cały kod, który nie uwzględnia 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, że zetknąłeś się z plikiem app.config obecnym 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.

Na szczęście dla Ciebie, język C# i ekosystem .NET zawierają funkcje i techniki, które pozwalają nam łatwo dostosować naszą aplikację, aby działała 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 wią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ć wersji 1.0.1 poprawki ReferencedLibrary zamiast wersji 1.0.0, z 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 binarnie zgodna z twoją aplikacją. Zobacz sekcję Zgodność z poprzednimi wersjami powyżej, aby zapoznać się ze zmianami podczas określania zgodności.

nowe

Używasz modyfikatora new, aby ukryć dziedziczone składowe 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 można zobaczyć, jak DerivedClass ukrywa metodę MyMethod w BaseClass. 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 nie zostanie określony modyfikator new, klasa pochodna domyślnie ukryje sprzeczne elementy członkowskie w klasie bazowej, i choć 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.

zastąpienie

Modyfikator override oznacza, że implementacja pochodna rozszerza implementację członka klasy bazowej, zamiast ją ukrywać. Składowa klasy bazowej musi mieć zastosowany modyfikator virtual.

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: {b.MethodOne()}");
    Console.WriteLine($"Derived Method One: {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 składnika do zastąpienia.

Twoja wiedza na temat omówionych technik i zrozumienia sytuacji, w których można je zastosować, znacząco przyczyni się do ułatwienia przejścia między wersjami biblioteki.