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 průběhu své historie se rozhraní .NET pokusilo zachovat vysokou úroveň kompatibility od verze po verzi a napříč implementacemi .NET. I když se .NET 5 (a .NET Core) a novější verze dají považovat za novou technologii ve srovnání s rozhraním .NET Framework, dvě hlavní faktory omezují schopnost této implementace rozhraní .NET odcházet od rozhraní .NET Framework:
- Velký počet vývojářů, kteří původně vyvinuli nebo pokračovali v vývoji aplikací rozhraní .NET Framework. Očekávají konzistentní chování napříč implementacemi .NET.
- Projekty knihoven .NET Standard umožňují vývojářům vytvářet knihovny, které cílí na běžná rozhraní API sdílená rozhraním .NET Framework a .NET 5 (a .NET Core) a novějšími verzemi. Vývojáři očekávají, že knihovna používaná v aplikaci .NET by se měla chovat stejně jako stejná knihovna používaná v aplikaci .NET Framework.
Spolu s kompatibilitou napříč implementacemi .NET očekávají vývojáři vysokou úroveň kompatibility napříč verzemi dané implementace .NET. Kód napsaný pro starší verzi .NET Core by se měl bez problémů spouštět v .NET 5 nebo novější verzi. Ve skutečnosti mnoho vývojářů očekává, že nová rozhraní API nalezená v nově vydaných verzích rozhraní .NET by měla být také kompatibilní s předběžnými verzemi, ve kterých byla tato rozhraní API zavedena.
Tento článek popisuje změny, které ovlivňují kompatibilitu a způsob, jakým tým .NET vyhodnocuje jednotlivé typy změn. Pochopení toho, jak tým .NET přistupuje k možným zásadním změnám, je užitečný zejména pro vývojáře, kteří otevírají žádosti o přijetí změn, které upravují chování stávajících rozhraní .NET API.
Následující části popisují kategorie změn provedených v rozhraních .NET API a jejich dopad na kompatibilitu aplikací. Změny jsou buď povolené (), nepovolené (✔️❌), nebo vyžadují úsudek a vyhodnocení toho, jak předvídatelné, zřejmé a konzistentní bylo předchozí chování (❓).
Poznámka:
- Kromě toho, že slouží jako průvodce vyhodnocováním změn knihoven .NET, mohou vývojáři knihoven tato kritéria použít také k vyhodnocení změn knihoven, které cílí na více implementací a verzí .NET.
- Informace o kategoriích kompatibility, například dopředné a zpětné kompatibility, naleznete v tématu Jak můžou změny kódu ovlivnit kompatibilitu.
Úpravy veřejné zakázky
Změny v této kategorii upravují veřejnou plochu typu. Většina změn v této kategorii je zakázána, protože porušují zpětnou kompatibilitu (schopnost aplikace vyvinuté s předchozí verzí rozhraní API ke spuštění bez rekompilace u novější verze).
Typy
✔️ POVOLENO: Odebrání implementace rozhraní z typu, pokud rozhraní je již implementováno základním typem
❓ VYŽADUJE ÚSUDEK: Přidání nové implementace rozhraní do typu
Jedná se o přijatelnou změnu, protože nemá nepříznivý vliv na stávající klienty. Všechny změny typu musí fungovat v rámci hranic přijatelných změn definovaných zde, aby nová implementace zůstala přijatelná. Je extrémně důležité být opatrný při přidávání rozhraní, která přímo ovlivňují schopnosti návrháře nebo serializátoru generovat kód nebo data, jež nelze využívat na nižších úrovních. Příkladem je ISerializable rozhraní.
❓ VYŽADUJE ÚSUDEK: Představujeme novou základní třídu.
Typ lze zavést do hierarchie mezi dvěma existujícími typy, pokud nezavádějí žádné nové abstraktní členy nebo nemění sémantiku nebo chování existujících typů. Například v rozhraní .NET Framework 2.0 se třída DbConnection stala novou základní třídou pro SqlConnection, která byla dříve odvozena přímo z Component.
✔️ POVOLENO: Přesunutí typu z jednoho sestavení do druhého
Staré sestavení musí být označeno odkazem TypeForwardedToAttribute na nové sestavení.
✔️ POVOLENO: Změna typu struktury na
readonly structtypreadonly structZměna typu nastructtyp není povolená.✔️ POVOLENO: Přidání zapečetěného nebo abstraktního klíčového slova do typu, pokud nejsou k dispozici žádné přístupné (veřejné nebo chráněné) konstruktory
✔️ POVOLENO: Rozšíření viditelnosti typu
❌ NEDOVOLENO: Změnit obor názvů nebo název typu
❌ ZAKÁZÁNO: Veřejný typ nelze přejmenovat nebo odebrat
Tím se přeruší veškerý kód, který používá přejmenovaný nebo odebraný typ.
Poznámka:
Ve výjimečných případech může .NET odebrat veřejné rozhraní API. Další informace najdete v tématu Odebrání rozhraní API v .NET. Informace o zásadách podpory .NET najdete v tématu Zásady podpory .NET.
❌ DISALLOWED: Změna základního typu výčtu
Jedná se o změnu, která způsobuje chyby při kompilaci, narušuje běh programu a mění binární kompatibilitu, což může způsobit, že argumenty atributů budou neinterpretovatelné.
❌ ZAKÁZÁNO: Zapečetění typu, který byl dříve nezapečetěn
❌ DISALLOWED: Přidání rozhraní do sady základních typů rozhraní
Pokud rozhraní začne implementovat jiné rozhraní, které dříve neimplementovalo, všechny typy, které původní verzi rozhraní implementovaly, se rozbijí.
❓ VYŽADUJE ÚSUDEK: Odebrání třídy ze sady základních tříd nebo rozhraní ze sady implementovaných rozhraní
Existuje jedna výjimka pravidla pro odebrání rozhraní: můžete přidat implementaci rozhraní, které je odvozeno z odebraného rozhraní. Můžete například odebrat IDisposable , pokud typ nebo rozhraní nyní implementuje IComponent, který implementuje IDisposable.
❌ DISALLOWED: Změna
readonly structtypu na typ structZměna typu
structna typreadonly structje však povolená.❌ NEPOVOLENO: Změna typu struct na typ
ref struct, a naopak❌ ZAKÁZÁNO: Snížení viditelnosti typu
Zvýšení viditelnosti typu je však povoleno.
Členové
✔️ POVOLENO: Rozšíření viditelnosti člena, který není virtuální
✔️ POVOLENO: Přidání abstraktního členu do veřejného typu, který nemá přístupné (veřejné nebo chráněné) konstruktory nebo je typ zapečetěn
Přidání abstraktního členu do typu, který má přístupné (veřejné nebo chráněné) konstruktory, není
sealedpovoleno.✔️ POVOLENO: Omezení viditelnosti chráněného členu, pokud typ nemá přístupné (veřejné nebo chráněné) konstruktory nebo je typ zapečetěn.
✔️ POVOLENO: Přesunutí člena do vyšší třídy v hierarchii než typ, ze kterého byl odebrán
✔️ POVOLENO: Přidání nebo odebrání přepsání
Zavedení přepsání může způsobit, že předchozí příjemci přeskočili přepsání při volání základu.
✔️ POVOLENO: Přidání konstruktoru do třídy spolu s konstruktorem bez parametrů, pokud třída dříve neměla žádné konstruktory
Přidání konstruktoru do třídy, která dříve žádné konstruktory neměla, bez přidání konstruktoru bez parametrů, není dovoleno.
✔️ POVOLENO: Změna člena z abstraktního na virtuální
✔️ POVOLENO: Změna z
ref readonlyhodnoty na návratovourefhodnotu (s výjimkou virtuálních metod nebo rozhraní)✔️ POVOLENO: Odebrání atributu readonly z pole, pokud statický typ pole není typem s měnitelnou hodnotou
✔️ POVOLENO: Volání nové události, která nebyla dříve definována
❓ VYŽADUJE ROZSUDEK: Přidání nového pole instance do typu
Tato změna má vliv na serializaci.
❌ DISALLOWED: Přejmenování nebo odebrání veřejného člena nebo parametru
Tím se přeruší veškerý kód, který používá přejmenovaný nebo odebraný člen nebo parametr.
To zahrnuje odebrání nebo přejmenování getteru nebo setter z vlastnosti a také přejmenování nebo odebrání členů výčtu.
❓ VYŽADUJE ÚSUDEK: Přidání člena do rozhraní
I když jde o zásadní změnu v tom smyslu, že zvýší minimální verzi .NET na .NET Core 3.0 (C# 8.0), což je, když byly zavedeny výchozí členy rozhraní (DIM), přidání statického, ne abstraktního, ne-virtuálního člena do rozhraní je povoleno.
Pokud zadáte implementaci, přidání nového člena do existujícího rozhraní nemusí nutně způsobit selhání kompilace v následných sestaveních. Ne všechny jazyky však podporují dimy. V některých scénářích se modul runtime také nemůže rozhodnout, který výchozí člen rozhraní se má vyvolat. V některých scénářích se rozhraní implementují podle
ref structtypů. Vzhledem k tomuref struct, že typy nelze zavádět do rámečku, není možné je převést na typy rozhraní.ref structProto typy musí poskytovat implicitní implementaci pro každý člen rozhraní. Nemůžou použít výchozí implementaci poskytovanou rozhraním. Z těchto důvodů je třeba používat úsudek při přidávání člena do existujícího rozhraní.❌ ZAKÁZÁNO: Změna hodnoty veřejné konstanty nebo člena výčtu
❌ ZAKÁZÁNO: Změna typu vlastnosti, pole, parametru nebo návratové hodnoty
❌ ZAKÁZÁNO: Přidání, odebrání nebo změna pořadí parametrů
❌ ZAKÁZÁNO: Přidání nebo odebrání klíčového slova in, out nebo ref z parametru
❌ DISALLOWED: Přejmenování parametru (včetně změny jeho/její velikosti písmen)
To se považuje za zásadní ze dvou důvodů:
Přeruší zpožděné scénáře, jako je funkce pozdní vazby v jazyce Visual Basic a dynamická v jazyce C#.
Přeruší kompatibilitu zdroje , když vývojáři používají pojmenované argumenty.
❌ ZAKÁZÁNO: Změna z návratové
refhodnoty na návratovouref readonlyhodnotu❌️ NEPOVOLENÉ: Změna vrácené hodnoty z
ref readonlynarefu virtuální metody nebo rozhraní❌ ZAKÁZÁNO: Přidání nebo odebrání abstrakce ze člena
❌ ZAKÁZÁNO: Odebrání virtuálního klíčového slova ze člena
❌ ZAKÁZÁNO: Přidání virtuálního klíčového slova do člena
I když to často není zásadní změna, protože kompilátor jazyka C# má tendenci generovat instrukce callvirt Intermediate Language (IL) pro volání nevirtuální metody (
callvirtprovádí kontrolu null, zatímco normální volání není), toto chování není z několika důvodů neměnné:- C# není jediným jazykem, který je zaměřen na .NET.
- Kompilátor jazyka C# se stále častěji snaží optimalizovat
callvirtna normální volání, kdykoli cílová metoda není virtuální a pravděpodobně není null (například metoda, ke které lze přistupovat prostřednictvím operátoru šíření ?. null).
Vytvoření metody virtuální znamená, že kód příjemce by ji často volal nevirtuálně.
❌ ZAKÁZÁNO: Vytvoření abstraktního virtuálního člena
Virtuální člen poskytuje implementaci metody, kterou lze přepsat odvozenou třídou. Abstraktní člen neposkytuje žádnou implementaci a musí být překonfigurován.
❌ ZAKÁZÁNO: Přidání zapečetěného klíčového slova do člena rozhraní
Přidání
sealeddo výchozího členu rozhraní způsobí, že není virtuální, což brání volání implementace odvozeného typu daného člena.❌ ZAKÁZÁNO: Přidání abstraktního člena do veřejného typu, který má přístupné (veřejné nebo chráněné) konstruktory a který není zapečetěn
❌ ZAKÁZÁNO: Přidání nebo odebrání statického klíčového slova ze člena
❌ DISALLOWED: Přidání přetížení, které vylučuje existující přetížení a definuje jiné chování
Tím se způsobí problémy u stávajících klientů, kteří byli vázáni na předchozí přetížení. Pokud má například třída jednu verzi metody, která přijímá UInt32, stávající příjemce úspěšně vytvoří vazbu na toto přetížení při předání Int32 hodnoty. Pokud ale přidáte přetížení, které přijme Int32, při rekompilaci nebo použití pozdní vazby kompilátor nyní přiřadí nové přetížení. Pokud výsledkem je jiné chování, jde o kritickou změnu.
❌ DISALLOWED: Přidání konstruktoru do třídy, která dříve neměla žádný konstruktor, bez přidání konstruktoru bez parametrů
❌️ NEPOVOLENÉ: Přidání pouze pro čtení do textového pole
❌ ZAKÁZÁNO: Snížení viditelnosti člena
To zahrnuje snížení viditelnosti chráněného členu, pokud jsou dostupné (
publicneboprotected) konstruktory a typ nenízapečetěn. Pokud tomu tak není, omezení viditelnosti chráněného člena je povoleno.Zvýšení viditelnosti člena je povoleno.
❌ ZAKÁZÁNO: Změna typu člena
Návratovou hodnotu metody nebo typu vlastnosti nebo pole nelze změnit. Například deklarace metody, která vrací Object, nelze změnit, aby vracela String, a obráceně.
❌ DISALLOWED: Přidání pole instance do struktury, která neobsahuje žádná nepubliková pole
Pokud struktura obsahuje pouze veřejná pole nebo nemá vůbec žádná pole, volající mohou deklarovat místní hodnoty tohoto typu struktury bez volání konstruktoru struktury nebo první inicializace místního na
default(T), pokud jsou všechna veřejná pole nastavena na strukturu před prvním použitím. Přidání jakýchkoli nových polí – veřejných nebo soukromých – do takové struktury je změna narušující kompatibilitu zdroje pro volající, protože kompilátor bude požadovat inicializaci dalších polí.Dodatečně, přidání jakýchkoli nových polí – veřejných nebo neveřejných – do struktury bez polí nebo pouze veřejných polí je binární změna zásadní pro volající, kteří použili
[SkipLocalsInit]na svůj kód. Vzhledem k tomu, že kompilátor nebyl informován o těchto polích v době kompilace, mohl emitovat IL, který strukturu plně neinicializuje, což vede k vytvoření struktury z neinicializovaných dat zásobníku.Pokud má struktura jakákoli nepublikovaná pole, kompilátor již vynucuje inicializaci prostřednictvím konstruktoru nebo
default(T)a přidání nových polí instance není zásadní změnou.❌ ZAKÁZÁNO: Spuštění existující události, když nebyla nikdy dříve spuštěna
Změny chování
Shromáždění
✔️ POVOLENO: Učinit sestavení přenosným, pokud jsou stále podporovány stejné platformy
❌ ZAKÁZÁNO: Změna názvu sestavení
❌ ZAKÁZÁNO: Změna veřejného klíče sestavení
Vlastnosti, pole, parametry a návratové hodnoty
✔️ POVOLENO: Změna hodnoty vlastnosti, pole, návratové hodnoty nebo out parametru na odvozenější typ
Například metoda, která vrací typ Object může vrátit String instanci. (Podpis metody se však nemůže změnit.)
✔️ POVOLENO: Zvýšení rozsahu přijatých hodnot pro vlastnost nebo parametr, pokud člen není virtuální
Zatímco rozsah hodnot, které lze předat metodě nebo je člen může vrátit, se může rozšířit, typ parametru nebo člena nemůže. Například zatímco hodnoty předané metodě mohou rozšířit z 0-124 na 0-255, typ parametru se nemůže změnit z Byte na Int32.
❌ DISALLOWED: Rozšíření rozsahu přijatých hodnot pro vlastnost nebo parametr, pokud je člen virtuální
Tato změna přeruší stávající přepsané členy, které nebudou správně fungovat pro rozšířený rozsah hodnot.
❌ DISALLOWED: Snížení rozsahu platných hodnot pro vlastnosti nebo parametry
❌ DISALLOWED: Zvýšení rozsahu vrácených hodnot pro vlastnost, pole, návratovou hodnotu nebo out parametr
❌ DISALLOWED: Změna výchozí hodnoty vlastnosti, pole nebo parametru
Změna nebo odebrání výchozí hodnoty parametru nezpůsobí binární nekompatibilitu. Odebrání výchozí hodnoty parametru způsobí narušení zdrojového kódu a změna výchozí hodnoty parametru může vést k narušení chování po rekompilaci.
Z tohoto důvodu je odebrání výchozích hodnot parametru přijatelné v konkrétním případě "přesunutí" těchto výchozích hodnot do nového přetížení metody, aby se eliminovala nejednoznačnost. Představte si například existující metodu
MyMethod(int a = 1). Pokud zavádíte přetíženíMyMethodse dvěma volitelnými parametryaabmůžete zachovat kompatibilitu přesunutím výchozí hodnotyado nového přetížení. Nyní jsou dvě přetíženíMyMethod(int a)aMyMethod(int a = 1, int b = 2). Tento model umožňuje kompilovatMyMethod().❌ ZAKÁZÁNO: Změna přesnosti číselné návratové hodnoty
❓ VYŽADUJE ROZSUDEK: Změna analýzy vstupu a vyvolání nových výjimek (i když není v dokumentaci uvedeno chování analýzy
Výjimky
✔️ POVOLENO: Vyvolání odvozenější výjimky než existující výjimka
Vzhledem k tomu, že nová výjimka je podtřídou existující výjimky, předchozí kód zpracování výjimek bude nadále zpracovávat výjimku. Například v rozhraní .NET Framework 4 metody pro vytváření a načítání nastavení kultury začaly vyhazovat CultureNotFoundException místo ArgumentException, pokud nebyla nalezena daná kultura. Vzhledem k tomu, že CultureNotFoundException se odvozuje z ArgumentException, je to přijatelná změna.
✔️ POVOLENO: Vyvolání konkrétnější výjimky než NotSupportedException, NotImplementedExceptionNullReferenceException
✔️ POVOLENO: Vyvolání výjimky, která je považována za neobnovitelnou
Neopravitelné výjimky by neměly být zachyceny, ale místo toho by se měly zpracovávat centrální obsluhou na vysoké úrovni. Uživatelé proto nemají kód, který tyto explicitní výjimky zachytí. Neopravitelné výjimky jsou:
✔️ POVOLENO: Vyvolání nové výjimky v nové cestě kódu
Výjimka se musí vztahovat pouze na novou cestu kódu, která se spouští s novými hodnotami nebo stavem parametrů a která nemůže být spuštěna existujícím kódem, který cílí na předchozí verzi.
✔️ POVOLENO: Odebrání výjimky pro povolení robustnějšího chování nebo nových scénářů
Například metodu
Divide, která dříve zpracovávala pouze kladné hodnoty a hodila ArgumentOutOfRangeException jinak, lze změnit tak, aby podporovala záporné i kladné hodnoty bez vyvolání výjimky.✔️ POVOLENO: Změna textu chybové zprávy
Vývojáři by se neměli spoléhat na text chybových zpráv, které se také mění v závislosti na jazykové verzi uživatele.
❌ ZAKÁZÁNO: Vyvolání výjimky v jiném případě, který není uvedený výše
❌ ZAKÁZÁNO: Odebrání výjimky v jiném případě, který není uveden výše
Atributy
✔️ POVOLENO: Změna hodnoty atributu, který není pozorovatelný
❌ ZAKÁZÁNO: Změna hodnoty atributu, který je pozorovatelný
❓ VYŽADUJE ÚSUDEK: Odebrání atributu
Ve většině případů je odebrání atributu (například NonSerializedAttribute) zásadní změnou.
Podpora platformy
✔️ POVOLENO: Podpora operace na platformě, která se dříve nepodporovala
❌ ZAKÁZÁNO: Již nepodporuje nebo nyní vyžaduje konkrétní balíček Service Pack pro operaci, která byla dříve podporována na platformě.
Změny interní implementace
❓ VYŽADUJE ÚSUDEK: Změna povrchové plochy interního typu
Tyto změny jsou obecně povoleny, i když přerušují soukromé reflexe. V některých případech, kdy oblíbené knihovny třetích stran nebo velký počet vývojářů závisí na interních rozhraních API, nemusí být tyto změny povolené.
❓ VYŽADUJE POSOUZENÍ: Změna interní implementace člena
Tyto změny jsou obecně povolené, i když přerušují soukromé reflexe. V některých případech, kdy zákaznický kód často závisí na soukromé reflexi nebo kdy změna představuje nežádoucí vedlejší účinky, nemusí být tyto změny povoleny.
✔️ POVOLENO: Zlepšení výkonu operace
Schopnost upravit výkon operace je nezbytná, ale takové změny můžou přerušit kód, který závisí na aktuální rychlosti operace. To platí zejména pro kód, který závisí na načasování asynchronních operací. Změna výkonu by neměla mít žádný vliv na jiné chování daného rozhraní API; jinak bude změna narušující.
✔️ POVOLENO: Nepřímo (a často nepříznivě) mění výkon operace.
Pokud daná změna není z nějakého jiného důvodu považována za kritickou změnu, je to akceptovatelné. Často je potřeba provést akce, které můžou zahrnovat další operace nebo které přidávají nové funkce. To bude téměř vždy mít vliv na výkon, ale může být nezbytné, aby příslušné rozhraní API fungovalo podle očekávání.
❌ Nepovoleno: Změna synchronního rozhraní API na asynchronní (a naopak)
Změny kódu
✔️ POVOLENO: Přidání parametrů do parametru
❌ DISALLOWED: Přidání zaškrtnutého příkazu do bloku kódu
Tato změna může způsobit, že kód, který se dříve spustil, vyvolá výjimku OverflowException a je to nepřijatelné.
❌ ZAKÁZÁNO: Odebrání params z parametru
❌ ZAKÁZÁNO: Změna pořadí, ve kterém se události aktivují
Vývojáři můžou přiměřeně očekávat, že se události aktivují ve stejném pořadí a kód vývojáře často závisí na pořadí, ve kterém se události aktivují.
❌ ZAKÁZÁNO: Odebrání vyvolání události u dané akce
❌ ZAKÁZÁNO: Změna počtu uvedených volání událostí
❌ DISALLOWED: Přidání FlagsAttribute do typu výčtu