2016-07-04 6 views
5

Existe-t-il un moyen de mettre en cache le composant graphique MEF au démarrage de l'application (WPF), comme le MAF pour éviter de découvrir les répertoires et de construire le graphe des composants à chaque démarrage d'application. afin d'accélérer mon démarrage de l'application. MAF utilise AddinsStore pour stocker tous les ajouts, lorsque de nouveaux ajouts ont été détectés, le magasin a été reconstruit et enregistré à nouveau. Est-il possible de le faire avec une application modulaire conçue avec MEF?Mise en cache des composants MEF

EDIT:

dans mon architecture projet je extension, les modules et les services gérés Donc j'avoir des exportations comme (IExtension, IModule, IManagedService) et i gérer les dépendances de départ de tous les composants, ce qui Je veux précisément ex (Le répertoire des extensions) contient beaucoup de DLL et il est possible que toutes les DLL ne contiennent pas un (exportations/importations) car certaines des DLL ne sont que des références pour certaines extensions. donc le comportement de découverte par défaut de MEF est la recherche des exports/Importations dans tous les assemblys dans le répertoire Extension, mais je veux modifier ce comportement en regardant la première fois toutes les DLL et attraper les types et leurs noms et dll pour les utiliser l'heure de démarrage suivante. de la capture charger directement les composants (Exportations) afin que le MEF connaisse les composants disponibles et leurs emplacements sans charger et rechercher les DLL. il ressemble à un dictionnaire d'exportations et de leurs lieux et dépendances pour obtenir l'instance directement à partir de ses lieux (dll).

+0

Je ne comprends vraiment pas cette question ... Je n'ai jamais fait de MAF auparavant, mais beaucoup de MEF.Pourquoi ne pas simplement déplacer tous les composants MEF dans le même dossier et le charger directement à partir de là? Après avoir lu [this] (http://stackoverflow.com/questions/835182/choosing-between-mef-and-maf-system-addin), MAF semble être une façon compliquée et inutile de faire avancer les choses – lokusking

+0

Non je ne peux pas déplacez tous les assemblages dans un répertoire. J'utilise des catalogues d'annuaire et j'ai la structure qui coule: (extensions, modules, services gérés, SDK) dossiers, l'ordre de chargement important. –

+0

Vous pouvez également définir l'ordre de chargement dans Mef. Cela nécessite un peu de code moche, mais ça fonctionne. Si cela vous intéresse, faites le moi savoir et je posterai une réponse – lokusking

Répondre

1

Je ne sais pas si cela vous aidera à 100%, mais avec ce code, je contrôle l'ordre de chargement de mes modules.

Si vous pouvez contrôler votre charge commande, vous pourriez être en mesure de mettre tous vos années * .Dll dans le même dossier et gagner du temps, les trouvant dans les sous-dossiers:

La clé est l'utilisation de cet attribut supplémentaire: [ExportMetadata("Order", 1)]

Ensuite, votre plug-in devrait ressembler à ceci:

[Export(typeof(YourContract))] 
    [ExportMetadata("Order", 1)] 
    public class YourPlugin: YourContract{} 

Pour faire avancer les choses Loaded dans l'ordre, vous aurez besoin de quelque chose comme ceci:

Interface:

public interface IOrderMetadata { 
    [DefaultValue(int.MaxValue)] 
    int Order { 
     get; 
    } 
    } 

AdaptingCollection:

public class AdaptingCollection<T, M> : ICollection<Lazy<T, M>>, INotifyCollectionChanged { 
    /// <summary> 
    /// Constructor</summary> 
    public AdaptingCollection() 
     : this(null) { 
    } 

    /// <summary> 
    /// Constructor</summary> 
    /// <param name="adaptor">Function to apply to items in the collection</param> 
    public AdaptingCollection(Func<IEnumerable<Lazy<T, M>>, IEnumerable<Lazy<T, M>>> adaptor) { 
     this._mAdaptor = adaptor; 
    } 

    /// <summary> 
    /// CollectionChanged event for INotifyCollectionChanged</summary> 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    /// <summary> 
    /// Force the adaptor function to be run again</summary> 
    public void ReapplyAdaptor() { 
     if (this._mAdaptedItems == null) return; 
     this._mAdaptedItems = null; 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    #region ICollection Implementation 

    /// <summary> 
    /// Returns whether the item is present in the collection</summary> 
    /// <remarks>Accessors work directly against adapted collection</remarks> 
    /// <param name="item">Item to look for</param> 
    /// <returns>True if the item is in the collection</returns> 
    public bool Contains(Lazy<T, M> item) { 
     return this.AdaptedItems.Contains(item); 
    } 

    /// <summary> 
    /// Copies the entire list to a one-dimensional array, starting at the specified index of the target array</summary> 
    /// <remarks>Accessors work directly against adapted collection</remarks> 
    /// <param name="array">The target array</param> 
    /// <param name="arrayIndex">The starting index</param> 
    public void CopyTo(Lazy<T, M>[] array, int arrayIndex) { 
     this.AdaptedItems.CopyTo(array, arrayIndex); 
    } 

    /// <summary> 
    /// Gets the number of items in the collection</summary> 
    /// <remarks>Accessors work directly against adapted collection</remarks> 
    public int Count => this.AdaptedItems.Count; 

    /// <summary> 
    /// Gets whether the collection is read only.</summary> 
    /// <remarks>Accessors work directly against adapted collection</remarks> 
    public bool IsReadOnly => false; 

    /// <summary> 
    /// Gets an enumerator for the collection</summary> 
    /// <remarks>Accessors work directly against adapted collection</remarks> 
    /// <returns>The IEnumerator</returns> 
    public IEnumerator<Lazy<T, M>> GetEnumerator() { 
     return this.AdaptedItems.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() { 
     return this.GetEnumerator(); 
    } 

    /// <summary> 
    /// Add an item to the collection</summary> 
    /// <remarks>Mutation methods work against complete collection and then force 
    /// a reset of the adapted collection</remarks> 
    /// <param name="item">The item to add</param> 
    public void Add(Lazy<T, M> item) { 
     this._mAllItems.Add(item); 
     this.ReapplyAdaptor(); 
    } 

    /// <summary> 
    /// Clear all items from the collection</summary> 
    /// <remarks>Mutation methods work against complete collection and then force 
    /// a reset of the adapted collection</remarks> 
    public void Clear() { 
     this._mAllItems.Clear(); 
     this.ReapplyAdaptor(); 
    } 

    /// <summary> 
    /// Remove an item from the collection</summary> 
    /// <remarks>Mutation methods work against complete collection and then force 
    /// a reset of the adapted collection</remarks> 
    /// <param name="item">The item to remove</param> 
    /// <returns>True if the item was found, otherwise false</returns> 
    public bool Remove(Lazy<T, M> item) { 
     bool removed = this._mAllItems.Remove(item); 
     this.ReapplyAdaptor(); 
     return removed; 
    } 

    #endregion 

    /// <summary> 
    /// Invoke the adaptor function on the collection</summary> 
    /// <param name="collection">The collection to adapt</param> 
    /// <returns>The adapted collection</returns> 
    protected virtual IEnumerable<Lazy<T, M>> Adapt(IEnumerable<Lazy<T, M>> collection) { 
     if (this._mAdaptor != null) { 
     return this._mAdaptor.Invoke(collection); 
     } 

     return collection; 
    } 

    /// <summary> 
    /// Fire the CollectionChanged event</summary> 
    /// <param name="e">Event args</param> 
    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { 
     this.CollectionChanged?.Invoke(this, e); 
    } 

    private List<Lazy<T, M>> AdaptedItems => this._mAdaptedItems ?? (this._mAdaptedItems = this.Adapt(this._mAllItems).ToList()); 

    private readonly List<Lazy<T, M>> _mAllItems = new List<Lazy<T, M>>(); 
    private readonly Func<IEnumerable<Lazy<T, M>>, IEnumerable<Lazy<T, M>>> _mAdaptor; 
    private List<Lazy<T, M>> _mAdaptedItems; 

    } 

OderingCollection

public class OrderingCollection<T, M> : AdaptingCollection<T, M> { 
    /// <summary> 
    /// Constructor</summary> 
    /// <param name="keySelector">Key selector function</param> 
    /// <param name="descending">True to sort in descending order</param> 
    public OrderingCollection(Func<Lazy<T, M>, object> keySelector, bool descending = false) 
     : base(e => descending ? e.OrderByDescending(keySelector) : e.OrderBy(keySelector)) { 
    } 
    } 

Utilisation

[ImportMany(typeof(YourContract), AllowRecomposition = true)] 
    internal OrderingCollection<YourContract, IOrderMetadata> Plugins{ 
     get; private set; 
    } 

Dans votre Constructor:

this.Plugins= new OrderingCollection<ITemplateMapper, IOrderMetadata>(
          lazyRule => lazyRule.Metadata.Order); 

Mon chargement code (peut être différent du vôtre):

private void LoadModules() { 
     var aggregateCatalog = new AggregateCatalog(); 
     aggregateCatalog.Catalogs.Add(new DirectoryCatalog(".", "*.Plugin.*.dll")); 
     var container = new CompositionContainer(aggregateCatalog); 
     container.ComposeParts(this);  
    } 

J'espère que cela pourrait vous aider à vous débarrasser du CRG

+0

C'est une bonne idée mais cela ne m'a pas aidé à atteindre mes objectifs. J'ai ajouté plus de description dans ma question. regarde. –

+0

Selon votre modification, vous pouvez configurer une petite base de données contenant les plugins installés et leurs chemins. Après cela, vous devriez être capable de les charger directement sans ramper vos dossiers – lokusking

+0

Ai-je raison si je disais: MEF lors de la composition d'une partie, il va essayer de rechercher ses importations et exportations et dépendances puis il va créer l'instance? –