2012-10-18 15 views
5

Moja aplikacja składa się z kilku podstawowych zespołów i kilku złożeń rozszerzeń/wtyczek. Aby MEF mógł poznać wszystkie części, które ma do zaoferowania wtyczka, muszę załadować te zespoły, nawet jeśli nigdy nie zamierzam używać żadnej z ich części. To sprawia, że ​​uruchomienie aplikacji zajmuje więcej czasu (jeśli mam załadować wszystkie zestawy podczas uruchamiania), a także zwiększa ślad pamięci.Leniwe ładowanie zestawów/katalogów

Idealnie nie będę musiał ładować zespołów, dopóki ich faktycznie nie potrzebuję. Załadowałbym tylko dane eksportu wtyczek, a kiedy faktycznie potrzebuję zaimportować część, MEF załadowałby zespół i zapewniłby część.

Znalazłem coś, co robi prawie wszystko, co właśnie napisałem, ale po zapytaniu o to w MEF CachedAssemblyCatalog - Lazy Loading of Assemblies, zdałem sobie sprawę, że ten kod nie jest uważany za stabilny i nie jest utrzymywany przez zespół MEF, więc mam postanowiłam go nie używać.

Moje pytanie brzmi jak to mogę osiągnąć to zachowanie:

  • Będąc w stanie uzyskać dostęp do metadanych eksportowej złożeń wtyczki bez ładowania cały ich montaż.
  • Przejrzysta integracja z kodem importującym części; tj. importować jak zwykle - ktoś inny (wyspecjalizowany katalog?) zajmie się ładowaniem zespołów, jeśli to konieczne, i dostarczy żądaną część.
  • nie tracąc żadnej istniejącej MEF funkcjonalności takich jak rekompozycję, leniwy typów itp

jestem całkowicie w porządku z rozwiązania, które wymaga parsowania wtyczek z wyprzedzeniem, aby stworzyć zespół metadanych pliku XML lub etażerka.

Odpowiedz

2

Jeśli zaraz po załadowaniu zespołów wystąpią opóźnienia, możliwe, że część rozwiązań zostanie wykorzystana na this question. Nie trzeba pobierać wszystkich informacji pobranych z tego rozwiązania. Prawdopodobnie tylko nazwa kontraktu, nazwa zespołu i czy część eksportuje lub importuje kontrakt. Następnie można napisać katalog, który ładuje zespoły jak ich potrzebujesz, na przykład tak:

public sealed class DelayLoadingCatalog : ComposablePartCatalog 
{ 
    // List containing tuples which have the 'contract name' 
    // and the 'assembly name' 
    private readonly List<Tuple<string, string>> m_Plugins 
     = new List<Tuple<string, string>>(); 
    private readonly Dictionary<string, AssemblyCatalog> m_Catalogs 
     = new Dictionary<string, AssemblyCatalog>(); 

    public DelayLoadingCatalog(IEnumerable<Tuple<string, string>> plugins) 
    { 
     m_Plugins.AddRange(plugins); 
    } 

    public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) 
    { 
     var partsToLoad = m_Plugins 
      .Where(t => t.Item1.Equals(definition.ContractName)); 
     foreach (var part in partsToLoad) 
     { 
      if (!m_Catalogs.ContainsKey(part.Item2.Name)) 
      { 
       var assembly = Assembly.Load(new AssemblyName(part.Item2.Name)); 
       m_Catalogs.Add(part.Item2.Name, new AssemblyCatalog(assembly)); 
      } 
     } 

     return m_Catalogs.SelectMany(p => p.Value.GetExports(definition)); 
    } 

    public override IQueryable<ComposablePartDefinition> Parts 
    { 
     get 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

które można następnie wykorzystać jak to

class Program 
{ 
    public void Init() 
    { 
     var domainSetup = new AppDomainSetup 
     { 
      ApplicationBase = Directory.GetCurrentDirectory(), 
     }; 

     var scanDomain = AppDomain.CreateDomain(
      "scanDomain", 
      null, 
      domainSetup); 
     var scanner = scanDomain.CreateInstanceAndUnwrap(
      typeof(MyScanner).Assembly.FullName, 
      typeof(MyScanner).FullName) as MyScanner; 
     var plugins = scanner.Scan(myPluginsPath); 

     // Make sure we don't have the assemblies loaded anymore ... 
     AppDomain.Unload(scanDomain); 

     var catalog = new DelayLoadingCatalog(plugins); 
     var container = new CompositionContainer(catalog); 

     container.ComposeParts(this); 
    } 

    [Import("MyCoolExport")] 
    public object MyImport 
    { 
     get; 
     set; 
    } 
} 

przykładzie DelayLoadCatalog nie jest bardzo mądry jak będzie przeszukiwać listę krotek. Optymalizacja kodu nie powinna być jednak zbyt trudna. Na przykład możesz jednak sprawdzić, czy wszystkie złożenia zostały załadowane i przestać przeszukiwać tę listę w tym momencie.

+0

Hej Petrik, bardzo dziękuję za pomoc! Natknąłem się na pytanie, które dołączyłeś jakiś czas temu i bardzo mi pomogło w rozwiązaniu tego problemu. To, co robiłem, było podobne do tego, co tam opisałeś - serializowałem dane do pliku i utworzyłem nowy katalog, który pochłania ten plik. W ten sposób dostępne są wszystkie eksporty, w tym metadane, i za pomocą interfejsu API "ReflectionModelServices" wszystko zostało załadowane leniwie. To wydaje się najlepszym sposobem na spełnienie moich wymagań. Mam nadzieję, że będę miał trochę czasu, aby odpowiedzieć na to pytanie osobiście, dzięki temu, co zrobiłem. Dzięki jeszcze raz! –

0

Jeśli ktoś jest zainteresowany, sam zaimplementowałem rozwiązanie i udostępniłem je ostatnio na GitHub. Rozwiązanie LazyAssemblyLoading umożliwia użytkownikowi serializację informacji o elemencie zespołu, a następnie użycie go do zainicjowania elementu LazyAssemblyCatalog, który będzie ładował zespół tylko wtedy, gdy jedna z jego części jest rzeczywiście wymagana, a jednocześnie pozwala na używanie metadanych w zwykły sposób, podczas gdy zestaw nie jest załadowany.

Powiązane problemy