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 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.PATCH
składnika 3, gdzie:
MAJOR
jest zwiększana w przypadku wprowadzania niezgodnych zmian interfejsu APIMINOR
funkcja jest zwiększana w przypadku dodawania funkcji w sposób zgodny z poprzednimi wersjamiPATCH
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.
nowe
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 BaseClass
pliku .
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.