Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto kurzu se dozvíte, co znamená správa verzí v .NET. Dozvíte se také o faktorech, které je potřeba vzít v úvahu při správě verzí knihovny a také při upgradu na novou verzi knihovny.
Jazyková verze
Kompilátor jazyka C# je součástí sady .NET SDK. Kompilátor ve výchozím nastavení zvolí jazykovou verzi jazyka C#, která odpovídá zvolenému TFM pro váš projekt. Pokud je verze sady SDK větší než vámi zvolená architektura, kompilátor může použít vyšší jazykovou verzi. Výchozí nastavení můžete změnit nastavením LangVersion prvku v projektu. V našem článku o možnostech kompilátoru se dozvíte, jak na to.
Varování
LangVersion Nastavení prvku na latest hodnotu se nedoporučuje. Nastavení latest znamená, že nainstalovaný kompilátor používá nejnovější verzi. To se může změnit z počítače na počítač a vytvářet nespolehlivé buildy. Kromě toho umožňuje funkce jazyka, které mohou vyžadovat funkce modulu runtime nebo knihovny, které nejsou součástí aktuální sady SDK.
Knihovny pro tvorbu obsahu
Jako vývojář, který vytvořil knihovny .NET pro veřejné použití, jste s největší pravděpodobností v situacích, kdy musíte zavést nové aktualizace. Na tomto procesu záleží hodně, protože potřebujete zajistit bezproblémový přechod existujícího kódu na novou verzi knihovny. Při vytváření nové verze je potřeba vzít v úvahu několik věcí:
Sémantická správa verzí
Semantic versioning (zkráceně SemVer) je pojmenovávací konvence použitá pro verze vaší knihovny, která označuje konkrétní významné milníky. V ideálním případě by informace o verzi, které knihovně poskytnete, měly pomoct vývojářům určit kompatibilitu s jejich projekty, které používají starší verze stejné knihovny.
Nejzásadnější přístup k SemVeru je formát MAJOR.MINOR.PATCH3 komponent , kde:
-
MAJORse zvýší, když provedete nekompatibilní změny rozhraní API. -
MINORse zvýší, když přidáváte funkce zpětně kompatibilním způsobem. -
PATCHse zvýší, když provedete zpětně kompatibilní opravy chyb.
Vysvětlení přírůstků verzí pomocí příkladů
Abychom vám pomohli objasnit, kdy zvýšit počet verzí, tady jsou konkrétní příklady:
Přírůstky verze MAJOR (nekompatibilní změny rozhraní API)
Tyto změny vyžadují, aby uživatelé upravili svůj kód, aby mohli pracovat s novou verzí:
Odebrání veřejné metody nebo vlastnosti:
// Version 1.0.0 public class Calculator { public int Add(int a, int b) => a + b; public int Subtract(int a, int b) => a - b; // This method exists } // Version 2.0.0 - MAJOR increment required public class Calculator { public int Add(int a, int b) => a + b; // Subtract method removed - breaking change! }Změna deklarace metody:
// Version 1.0.0 public void SaveFile(string filename) { } // Version 2.0.0 - MAJOR increment required public void SaveFile(string filename, bool overwrite) { } // Added required parameterZměna chování existujících metod způsobem, který by přerušil očekávání:
// Version 1.0.0 - returns null when file not found public string ReadFile(string path) => File.Exists(path) ? File.ReadAllText(path) : null; // Version 2.0.0 - MAJOR increment required public string ReadFile(string path) => File.ReadAllText(path); // Now throws exception when file not found
Minorní verze inkrementuje (zpětně kompatibilní funkcionalita)
Tyto změny přidávají nové funkce bez přerušení existujícího kódu:
Přidání nových veřejných metod nebo vlastností:
// Version 1.0.0 public class Calculator { public int Add(int a, int b) => a + b; } // Version 1.1.0 - MINOR increment public class Calculator { public int Add(int a, int b) => a + b; public int Multiply(int a, int b) => a * b; // New method added }Přidání nových přetížení:
// Version 1.0.0 public void Log(string message) { } // Version 1.1.0 - MINOR increment public void Log(string message) { } // Original method unchanged public void Log(string message, LogLevel level) { } // New overload addedPřidání volitelných parametrů do existujících metod:
// Version 1.0.0 public void SaveFile(string filename) { } // Version 1.1.0 - MINOR increment public void SaveFile(string filename, bool overwrite = false) { } // Optional parameterPoznámka:
Jedná se o zdrojovou kompatibilní změnu, ale binární zásadní změnu. Aby uživatelé této knihovny mohli správně pracovat, musí ji znovu zkompilovat. Mnoho knihoven by to považovalo pouze při změnách hlavní verze, nikoli při drobných změnách verze.
Přírůstky verzí typu PATCH (zpětně kompatibilní opravy chyb)
Tyto změny opravují problémy bez přidání nových funkcí nebo porušení stávajících funkcí:
Oprava chyby v implementaci existující metody:
// Version 1.0.0 - has a bug public int Divide(int a, int b) { return a / b; // Bug: doesn't handle division by zero } // Version 1.0.1 - PATCH increment public int Divide(int a, int b) { if (b == 0) throw new ArgumentException("Cannot divide by zero"); return a / b; // Bug fixed, behavior improved but API unchanged }Vylepšení výkonu, která nemění rozhraní API:
// Version 1.0.0 public List<int> SortNumbers(List<int> numbers) { return numbers.OrderBy(x => x).ToList(); // Slower implementation } // Version 1.0.1 - PATCH increment public List<int> SortNumbers(List<int> numbers) { var result = new List<int>(numbers); result.Sort(); // Faster implementation, same API return result; }
Klíčovým principem je: pokud existující kód může používat novou verzi bez jakýchkoli změn, jedná se o aktualizaci MINOR nebo PATCH. Pokud je potřeba upravit stávající kód tak, aby fungoval s novou verzí, jedná se o aktualizaci MAJOR.
Existují také způsoby, jak určit jiné scénáře, například předběžné verze, při použití informací o verzi v knihovně .NET.
Zpětná kompatibilita
Při vydávání nových verzí vaší knihovny bude zpětná kompatibilita s předchozími verzemi pravděpodobně jedním z vašich hlavních problémů. Nová verze knihovny je zdroj kompatibilní s předchozí verzí, pokud kód, který závisí na předchozí verzi, může při rekompilování pracovat s novou verzí. Nová verze knihovny je binární kompatibilní, pokud aplikace, která závisí na staré verzi, může bez rekompilace pracovat s novou verzí.
Při pokusu o zachování zpětné kompatibility se staršími verzemi knihovny je potřeba vzít v úvahu několik věcí:
- Virtuální metody: Když ve své nové verzi uděláte z virtuální metody nevirtuální, znamená to, že projekty, které tuto metodu přepisují, budou muset být aktualizovány. Jedná se o obrovskou zásadní změnu a důrazně se nedoporučuje.
- Při aktualizaci chování metody, pokud je nutné změnit i její podpis, měli byste místo toho vytvořit přetížení, aby volání kódu do této metody nadále fungovalo. Se starým podpisem metody můžete vždy manipulovat a volat do nového podpisu metody, aby implementace zůstala konzistentní.
- Zastaralý atribut: Tento atribut v kódu můžete použít k určení tříd nebo členů třídy, které jsou zastaralé a pravděpodobně budou odebrány v budoucích verzích. Tím zajistíte, že vývojáři, kteří vaši knihovnu využívají, budou lépe připraveni na zásadní změny.
- Volitelné argumenty metody: Pokud zadáte dříve volitelné argumenty metody povinné nebo změníte jejich výchozí hodnotu, bude nutné aktualizovat veškerý kód, který tyto argumenty nezadá.
Poznámka:
Učinění povinných argumentů volitelnými by mělo mít velmi malý účinek, zvláště pokud nezmění chování metody.
Čím snazší bude pro uživatele přejít na novou verzi vaší knihovny, tím pravděpodobnější je, že přejdou dříve.
Konfigurační soubor aplikace
Jako vývojář .NET existuje velmi vysoká pravděpodobnost, že jste narazili na app.config soubor , který je ve většině typů projektů.
Tento jednoduchý konfigurační soubor může výrazně zlepšit nasazení nových aktualizací. Knihovny byste obecně měli navrhnout tak, aby informace, které se pravděpodobně budou pravidelně měnit, byly uloženy v app.config souboru, tímto způsobem při aktualizaci těchto informací, konfigurační soubor starších verzí je potřeba nahradit pouze novým, aniž by bylo nutné překompilace knihovny.
Využívání knihoven
Jako vývojář, který využívá knihovny .NET vytvořené jinými vývojáři, s největší pravděpodobností víte, že nová verze knihovny nemusí být plně kompatibilní s vaším projektem a často se může stát, že budete muset aktualizovat kód, aby tyto změny fungovaly.
Pro vás je prostředí C# a ekosystém .NET vybaveny funkcemi a technikami, které nám umožňují snadno aktualizovat naši aplikaci tak, aby fungovala s novými verzemi knihoven, které by mohly zavádět zásadní změny.
Přesměrování vazby sestavení
Pomocí souboru app.config můžete aktualizovat verzi knihovny, kterou vaše aplikace používá. Přidáním toho, co se nazývá přesměrování vazby, můžete použít novou verzi knihovny, aniž byste museli aplikaci znovu zkompilovat. Následující příklad ukazuje, jak byste aktualizovali soubor app.config vaší aplikace, aby používal patch verzi 1.0.1 namísto verze ReferencedLibrary, se kterou byl původně zkompilován.
<dependentAssembly>
<assemblyIdentity name="ReferencedLibrary" publicKeyToken="32ab4ba45e0a69a1" culture="en-us" />
<bindingRedirect oldVersion="1.0.0" newVersion="1.0.1" />
</dependentAssembly>
Poznámka:
Tento přístup bude fungovat jenom v případě, že nová verze ReferencedLibrary je binární kompatibilní s vaší aplikací.
Informace o změnách při určování kompatibility najdete v části Zpětná kompatibilita výše.
Nové…
Používáte modifikátor new ke skrytí zděděných členů základní třídy. Toto je jeden ze způsobů, jak odvozené třídy mohou reagovat na aktualizace v základních třídách.
Podívejte se na následující příklad:
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();
}
Výstup
A base method
A derived method
Z výše uvedeného příkladu vidíte, jak DerivedClass skryje metodu MyMethod , která je přítomna v BaseClass.
To znamená, že když základní třída v nové verzi knihovny přidá člena, který již existuje ve vaší odvozené třídě, můžete jednoduše použít new modifikátor u člena odvozené třídy ke skrytí člena základní třídy.
Pokud není zadán žádný new modifikátor, odvozená třída ve výchozím nastavení skryje konfliktní členy v základní třídě, i když se vygeneruje upozornění kompilátoru, kód bude stále kompilován. To znamená, že pouhé přidání nových členů do existující třídy způsobí, že nová verze knihovny bude zdrojová i binární kompatibilní s kódem, který na něm závisí.
přepsání
override Modifikátor znamená, že odvozená implementace člen základní třídy rozšiřuje, místo aby ho skryla. Člen základní třídy musí mít aplikovaný modifikátor 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()}");
}
Výstup
Base Method One: Method One
Derived Method One: Derived Method One
override Modifikátor se vyhodnocuje v době kompilace a kompilátor vyvolá chybu, pokud nenajde virtuálního člena, kterého má překrýt.
Vaše znalosti o probíraných technikách a porozumění situacím, ve kterých je použít, vám pomůžou zmírnit přechod mezi verzemi knihovny.