O system.Runtime.Loader.AssemblyLoadContext
Třída AssemblyLoadContext byla zavedena v .NET Core a není k dispozici v rozhraní .NET Framework. Tento článek doplňuje AssemblyLoadContext dokumentaci k rozhraní API koncepčními informacemi.
Tento článek je relevantní pro vývojáře, kteří implementuje dynamické načítání, zejména vývojáře architektury dynamického načítání.
Co je AssemblyLoadContext?
Každá aplikace .NET 5+ a .NET Core implicitně používá AssemblyLoadContext. Je to poskytovatel modulu runtime pro vyhledání a načítání závislostí. Při každém načtení závislosti se vyvolá instance, AssemblyLoadContext která ji vyhledá.
- AssemblyLoadContext poskytuje službu vyhledání, načítání a ukládání spravovaných sestavení do mezipaměti a dalších závislostí.
- Aby bylo možné podporovat dynamické načítání a uvolňování kódu, vytvoří izolovaný kontext pro načítání kódu a jeho závislostí ve vlastní AssemblyLoadContext instanci.
Pravidla správy verzí
Jedna AssemblyLoadContext instance je omezena na načtení přesně jedné verze jednoho Assemblynázvu sestavení. Pokud je odkaz na sestavení vyřešen proti AssemblyLoadContext instanci, která již má sestavení tohoto názvu načteno, je požadovaná verze porovnána s načtenou verzí. Řešení bude úspěšné pouze v případě, že načtená verze je stejná nebo vyšší než požadovaná verze.
Kdy potřebujete více instancí AssemblyLoadContext?
Omezení, že jedna AssemblyLoadContext instance může načíst pouze jednu verzi sestavení, může být problém při dynamickém načítání modulů kódu. Každý modul je nezávisle kompilován a moduly mohou záviset na různých verzích Assembly. To je často problém, když různé moduly závisí na různých verzích běžně používané knihovny.
Pro podporu dynamického načítání kódu AssemblyLoadContext poskytuje rozhraní API pro načítání konfliktních verzí ve Assembly stejné aplikaci. Každá AssemblyLoadContext instance poskytuje jedinečný slovník, který každý AssemblyName.Name mapuje na konkrétní Assembly instanci.
Poskytuje také pohodlný mechanismus pro seskupování závislostí souvisejících s modulem kódu pro pozdější uvolnění.
Instance AssemblyLoadContext.Default
Instance AssemblyLoadContext.Default se při spuštění automaticky naplní modulem runtime. Používá výchozí sondování k vyhledání a vyhledání všech statických závislostí.
Řeší nejběžnější scénáře načítání závislostí.
Dynamické závislosti
AssemblyLoadContext obsahuje různé události a virtuální funkce, které je možné přepsat.
Instance AssemblyLoadContext.Default podporuje pouze přepsání událostí.
Články Spravovaný algoritmus načítání sestavení, algoritmus načítání satelitního sestavení a nespravovaný (nativní) algoritmus načítání knihovny odkazují na všechny dostupné události a virtuální funkce. Články zobrazují relativní pozici každé události a funkce v algoritmech načítání. Tento článek tyto informace nereprodukuje.
Tato část se zabývá obecnými principy relevantních událostí a funkcí.
- Opakovatelné. Dotaz na konkrétní závislost musí vždy vést ke stejné odpovědi. Musí se vrátit stejná načtená instance závislostí. Tento požadavek je zásadní pro konzistenci mezipaměti. Pro spravovaná sestavení zejména vytváříme Assembly mezipaměť. Klíč mezipaměti je jednoduchý název sestavení . AssemblyName.Name
- Obvykle se nehodí. Očekává se, že tyto funkce se vrátí
null
místo vyvolání, když nelze najít požadovanou závislost. Vyvolání předčasně ukončí vyhledávání a rozšíří výjimku volajícímu. Vyvolání by mělo být omezeno na neočekávané chyby, jako je poškozené sestavení nebo nedostatek paměti. - Vyhněte se rekurzi. Mějte na paměti, že tyto funkce a obslužné rutiny implementují pravidla načítání pro vyhledání závislostí. Vaše implementace by neměla volat rozhraní API, která aktivují rekurz. Váš kód by obvykle měl volat Funkce načtení AssemblyLoadContext , které vyžadují konkrétní cestu nebo referenční argument paměti.
- Načtěte do správného AssemblyLoadContextu. Volba místa, kde se mají načítat závislosti, je specifická pro aplikaci. Volba je implementována těmito událostmi a funkcemi. Když váš kód volá AssemblyLoadContext load-by-path funkce, volají je v instanci, ve které chcete kód načíst. Někdy se může vrátit
null
a nechat AssemblyLoadContext.Default popisovač zatížení nejjednodušší možností. - Mějte na paměti závody vláken. Načítání může být aktivováno více vlákny. AssemblyLoadContext zpracovává závody vláken atomicky přidáním sestavení do mezipaměti. Instance losera závodu je zahozena. V logice implementace nepřidávejte další logiku, která nezpracuje více vláken správně.
Jak jsou dynamické závislosti izolované?
Každá AssemblyLoadContext instance představuje jedinečný obor pro Assembly instance a Type definice.
Mezi těmito závislostmi neexistuje žádná binární izolace. Jsou izolované jenom tím, že se navzájem nenajdou podle názvu.
V každém AssemblyLoadContextz nich:
- AssemblyName.Name může odkazovat na jinou Assembly instanci.
- Type.GetType může vrátit jinou instanci typu pro stejný typ
name
.
Sdílené závislosti
Závislosti je možné snadno sdílet mezi AssemblyLoadContext instancemi. Obecný model je určený k AssemblyLoadContext načtení závislosti. Druhá sdílí závislost pomocí odkazu na načtené sestavení.
Toto sdílení je vyžadováno pro sestavení modulu runtime. Tato sestavení lze načíst pouze do AssemblyLoadContext.Defaultsouboru . Totéž se vyžaduje pro architektury, jako ASP.NET
je , WPF
nebo WinForms
.
Doporučuje se načíst sdílené závislosti do AssemblyLoadContext.Defaultsouboru . Toto sdílení je běžným vzorem návrhu.
Sdílení se implementuje v kódování vlastní AssemblyLoadContext instance. AssemblyLoadContext obsahuje různé události a virtuální funkce, které je možné přepsat. Pokud některé z těchto funkcí vrátí odkaz na Assembly instanci, která byla načtena v jiné AssemblyLoadContext instanci, Assembly instance se sdílí. Standardní algoritmus zatížení se odkláněl k AssemblyLoadContext.Default načtení, aby zjednodušil běžný způsob sdílení. Další informace naleznete v tématu Algoritmus načítání spravovaných sestavení.
Problémy s převodem typu
Pokud dvě AssemblyLoadContext instance obsahují definice typu se stejným name
typem, nejedná se o stejný typ. Jsou stejného typu, pokud a pouze pokud pocházejí ze stejné Assembly instance.
Pokud chcete komplikovat důležité věci, můžou být zprávy o výjimce o těchto neshodných typech matoucí. Typy jsou odkazovány ve zprávách o výjimce jejich jednoduchými názvy typů. Běžná zpráva o výjimce v tomto případě je ve formuláři:
Objekt typu IsolatedType nelze převést na typ IsolatedType.
Ladění problémů s převodem typů
Vzhledem k páru neodpovídajících typů je důležité vědět také:
- Každý typ Type.Assemblyje .
- Každý typ AssemblyLoadContext, který lze získat prostřednictvím AssemblyLoadContext.GetLoadContext(Assembly) funkce.
Vzhledem k dvěma objektům a
a b
vyhodnocení následujících hodnot v ladicím programu bude užitečné:
// In debugger look at each assembly's instance, Location, and FullName
a.GetType().Assembly
b.GetType().Assembly
// In debugger look at each AssemblyLoadContext's instance and name
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(a.GetType().Assembly)
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(b.GetType().Assembly)
Řešení problémů s převodem typů
Existují dva vzory návrhu pro řešení těchto problémů s převodem typů.
Používejte běžné sdílené typy. Tento sdílený typ může být buď primitivním typem modulu runtime, nebo může zahrnovat vytvoření nového sdíleného typu ve sdíleném sestavení. Sdílený typ je často rozhraní definované v sestavení aplikace. Další informace najdete v tématu o sdílení závislostí.
Pomocí technik seřazování můžete převést z jednoho typu na jiný.