Udostępnij za pomocą


Informacje o pliku System.Runtime.Loader.AssemblyLoadContext

Klasa została wprowadzona AssemblyLoadContext na platformie .NET Core i nie jest dostępna w programie .NET Framework. Ten artykuł uzupełnia dokumentację interfejsu AssemblyLoadContext API informacjami koncepcyjnymi.

Ten artykuł jest istotny dla deweloperów wdrażających ładowanie dynamiczne, zwłaszcza deweloperów platform ładowania dynamicznego.

Co to jest AssemblyLoadContext?

Każda aplikacja .NET 5+ i .NET Core niejawnie używa metody AssemblyLoadContext. Jest to dostawca środowiska uruchomieniowego do lokalizowania i ładowania zależności. Za każdym razem, gdy ładowana jest zależność, instancja AssemblyLoadContext jest wywoływana, aby ją zlokalizować.

  • AssemblyLoadContext udostępnia usługę lokalizowania, ładowania i buforowania zarządzanych zestawów oraz innych zależności.
  • Aby obsługiwać dynamiczne ładowanie i zwalnianie kodu, tworzy izolowany kontekst ładowania kodu i jego zależności we własnym AssemblyLoadContext wystąpieniu.

Reguły przechowywania wersji

Pojedyncze AssemblyLoadContext wystąpienie jest ograniczone do załadowania dokładnie jednej wersji Assembly dla prostej nazwy zestawu. Jeśli odwołanie do zestawu zostanie rozpoznane względem AssemblyLoadContext wystąpienia, które ma już załadowany zestaw o tej samej nazwie, porównuje się żądaną wersję z załadowaną wersją. Rozwiązanie powiedzie się tylko wtedy, gdy załadowana wersja jest równa lub wyższa od żądanej wersji.

Kiedy potrzebujesz wielu wystąpień AssemblyLoadContext?

Ograniczenie, że pojedyncze AssemblyLoadContext wystąpienie może załadować tylko jedną wersję zestawu, może stać się problemem podczas dynamicznego ładowania modułów kodu. Każdy moduł jest kompilowany niezależnie, a moduły mogą zależeć od różnych wersji elementu Assembly. Jest to często problem, gdy różne moduły zależą od różnych wersji powszechnie używanej biblioteki.

Aby obsługiwać dynamiczne ładowanie kodu, interfejs API AssemblyLoadContext umożliwia ładowanie sprzecznych wersji elementu o nazwie Assembly w ramach tej samej aplikacji. Każde AssemblyLoadContext wystąpienie udostępnia unikatowy słownik, który mapuje każdy AssemblyName.Name na określone Assembly wystąpienie.

Zapewnia również wygodny mechanizm grupowania zależności związanych z modułem kodu dla późniejszego rozładowania.

Instancja AssemblyLoadContext.Default

Wystąpienie AssemblyLoadContext.Default jest automatycznie wypełniane przez środowisko uruchomieniowe podczas uruchamiania. Używa ona domyślnego sondowania do lokalizowania i znajdowania wszystkich zależności statycznych.

Rozwiązuje to typowe scenariusze ładowania zależności.

Zależności dynamiczne

AssemblyLoadContext ma różne zdarzenia i funkcje wirtualne, które mogą zostać zastąpione.

Wystąpienie AssemblyLoadContext.Default obsługuje tylko zastępowanie zdarzeń.

Artykuły Managed assembly loading algorithm (Algorytm ładowania zestawu zarządzanego), Satellite assembly loading algorithm(Algorytm ładowania zestawu satelitarnego) i Unmanaged (natywny) algorytm ładowania biblioteki odwołują się do wszystkich dostępnych zdarzeń i funkcji wirtualnych. W artykułach przedstawiono względne położenie poszczególnych zdarzeń i funkcji w algorytmach ładowania. Ten artykuł nie odtworzy tych informacji.

W tej sekcji omówiono ogólne zasady dotyczące odpowiednich zdarzeń i funkcji.

  • Bądź powtarzalny. Zapytanie dotyczące określonej zależności musi zawsze powodować tę samą odpowiedź. Należy zwrócić tę samą załadowaną instancję zależności. To wymaganie jest kluczowe dla spójności pamięci podręcznej. W szczególności w przypadku zestawów zarządzanych tworzymy pamięć podręczną Assembly . Klucz pamięci podręcznej to prosta nazwa zestawu, AssemblyName.Name.
  • Zazwyczaj nie rzucaj. Oczekuje się, że te funkcje zwracają null zamiast zgłaszać wyjątek, gdy nie można odnaleźć żądanej zależności. Rzucenie przedwcześnie zakończy wyszukiwanie i przekazuje wyjątek do wywołującego. Zgłaszanie powinno być ograniczone do nieoczekiwanych błędów, takich jak uszkodzony zestaw lub stan braku pamięci.
  • Unikaj rekursji. Należy pamiętać, że te funkcje i programy obsługi implementują reguły ładowania na potrzeby lokalizowania zależności. Twoja implementacja nie powinna używać interfejsów API, które powodują rekursję. Kod powinien zwykle wywoływać funkcje ładowania AssemblyLoadContext , które wymagają określonej ścieżki lub argumentu odwołania do pamięci.
  • Załaduj do poprawnego kontekstu AssemblyLoadContext. Wybór miejsca ładowania zależności jest specyficzny dla aplikacji. Wybór jest implementowany przez te zdarzenia i funkcje. Kiedy twój kod wywołuje funkcje ładowania ścieżką w kontekście AssemblyLoadContext, wywołaj je na instancji, w której chcesz, aby kod został załadowany. Czasami zwracanie null i umożliwienie AssemblyLoadContext.Default obsługi zadania może być najprostszą opcją.
  • Zwróć uwagę na wyścigi wątków. Ładowanie może być wyzwalane przez wiele wątków. Kontekst ładowania AssemblyLoadContext obsługuje wyścigi wątków przez atomowe dodawanie zestawów do swojej pamięci podręcznej. Wystąpienie przegranego wyścigu jest odrzucane. W logice implementacji nie dodawaj dodatkowej logiki, która nie obsługuje poprawnie wielu wątków.

Jak izolowane są zależności dynamiczne?

Każde AssemblyLoadContext wystąpienie reprezentuje unikatowy zakres Assembly wystąpień i Type definicji.

Nie ma izolacji binarnej między tymi zależnościami. Są one odizolowane tylko przez nie znalezienie siebie nawzajem według nazwy.

W każdym z nich AssemblyLoadContext:

Wspólne zależności

Zależności można łatwo udostępniać między AssemblyLoadContext wystąpieniami. Ogólny model służy do tego, aby jeden AssemblyLoadContext ładował zależność. Inne współdzielą zależność przy użyciu odwołania do załadowanego zestawu.

To udostępnianie jest wymagane w zestawach środowiska uruchomieniowego. Te zestawy można załadować tylko do pliku AssemblyLoadContext.Default. To samo jest wymagane w przypadku struktur, takich jak ASP.NET, WPFlub WinForms.

Zaleca się załadowanie współużytkowanych zależności do AssemblyLoadContext.Default. To udostępnianie jest typowym wzorcem projektowania.

Udostępnianie jest zaimplementowane w kodzie instancji niestandardowej AssemblyLoadContext. AssemblyLoadContext ma różne zdarzenia i funkcje wirtualne, które mogą zostać zastąpione. Gdy którakolwiek z tych funkcji zwraca odwołanie do wystąpienia Assembly, które zostało załadowane w innym wystąpieniu AssemblyLoadContext, współużytkowane jest wystąpienie Assembly. Standardowy algorytm ładowania opiera się na AssemblyLoadContext.Default w celu uproszczenia wspólnego wzorca udostępniania. Aby uzyskać więcej informacji, zobacz Managed assembly loading algorithm (Algorytm ładowania zestawu zarządzanego).

Problemy przy konwersji typów

Gdy dwa AssemblyLoadContext wystąpienia zawierają definicje typów o tym samym nametypie, nie są tego samego typu. Są one tego samego typu, jeśli i tylko wtedy, gdy pochodzą z tego samego Assembly wystąpienia.

Aby skomplikować sprawy, komunikaty o wyjątkach dotyczące tych niezgodnych typów danych mogą być mylące. Typy są określane w komunikatach wyjątków według ich prostych nazw typów. Typowy komunikat o wyjątku w tym przypadku jest następujący:

Niemożliwe jest przekształcenie obiektu typu "IsolatedType" na typ "IsolatedType".

Debugowanie problemów z konwersją typu

Biorąc pod uwagę parę niezgodnych typów, ważne jest również, aby wiedzieć:

Biorąc pod uwagę dwa obiekty a i b, ocena następujących elementów w debugerze będzie przydatna:

// 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)

Rozwiąż problemy z konwersją typów

Istnieją dwa wzorce projektowe do rozwiązywania tych problemów z konwersją typów.

  1. Użyj typowych typów udostępnionych. Ten typ udostępniony może być typem pierwotnego środowiska uruchomieniowego lub może obejmować utworzenie nowego typu udostępnionego w zestawie udostępnionym. Często typ udostępniony jest interfejsem zdefiniowanym w zestawie aplikacji. Aby uzyskać więcej informacji, przeczytaj o sposobie udostępniania zależności.

  2. Użyj technik konwersji danych, aby przekonwertować z jednego typu na inny.