2010-01-26 6 views
4

Je me demande ce que la recommandation générale (attribut, interface, classe abstraite, ou une combinaison de ceux-ci) pour la mise en œuvre suivante:attribut, interface ou classe abstraite

/// <summary> 
    /// Loads class specific information into a list for serialization. The class must extend PlugIn. 
    /// The filenames parameter is passed from a FileDialog. 
    /// </summary> 
    /// <param name="filenames">Accepts any number of filenames with fully qualified paths.</param> 
    public static void ExtractPlugInData(params string[] filenames) 
    { 
    List<Type> l; 

    foreach (string f in filenames) 
    { 
    Assembly a = Assembly.LoadFrom(f); 
    // lambda expression selects any class within a library extending the abstract PlugIn class 
    l = a.GetTypes().Where(type => typeof(PlugIn).IsAssignableFrom(type)).ToList<Type>(); 

    if (l.Count > 0) 
      // write data to serializable class 
     WritePlugInData(f , l); 
    else 
     // throw exception 
     WriteLine("{0} :: No PlugIn Data Found" , a.FullName); 
      } 
    } 

Je me rends compte qu'il ya des avantages et inconvénients de chaque méthode. Évidemment, les attributs nécessitent une certaine réflexion (tout comme l'implémentation abstraite de l'extension et de l'interface). Une classe abstraite prend notre seul héritage de base, et tout changement futur dans une interface peut casser n'importe quel plugin existant. Donc, comme je le vois, ce sont les inconvénients.

Les performances ne sont pas un problème (à moins qu'il y ait quelque chose que je ne vois pas) puisque toute réflexion n'est effectuée qu'une fois lorsqu'une classe qualifiée est extraite. Les principaux éléments de données enregistrés sont le nom du plugin ("MyPlugIn"), l'espace de nom ("SuperPlugIn.PlugInClass") et le chemin de démarrage du fichier .dll. À l'heure actuelle, avec la classe PlugIn abstraite, l'extension des propriétés est appliquée. C'est plus ou moins le même résultat si on implémente une interface (IPlugIn).

Nous autorisons l'écriture de plugins personnalisés par les utilisateurs finaux. Avec les plugins que nous écrivons en interne, il est facile d'enseigner et de faire appliquer une structure requise pour notre application afin d'obtenir une classe qualifiée. Cependant, je considère également les difficultés ou les inconvénients pour l'utilisateur final en cas de changement majeur.

Tous les commentaires, suggestions et questions sont les bienvenus !!

Note: merci à Jon Skeet pour l'expression lambda dans l'extrait. :)

EDIT: J'aurais dû noter au début que cela devait être indépendant de la plate-forme (c'est-à-dire mono). MISE À JOUR: D'après les excellentes recommandations, commentaires et liens ci-dessous, une combinaison d'attributs et d'interfaces est la meilleure approche. Les attributs permettent de charger l'assemblage et de vérifier les informations et les implémentations requises de manière plutôt sûre sans avoir à instancier les classes/objets du plugin. Ceci est idéal dans les situations où des tiers ou des utilisateurs finaux sont autorisés à créer des plugins personnalisés. Nous pouvons vérifier que l'implémentation correcte du contrat est en place lorsque l'attribut indique qu'il est supposé l'être. Nous pouvons vérifier les dépendances et les ressources requises et alerter le développeur de tout problème avant que l'on instance quoi que ce soit.

+0

Je suis sûr que ce ne sera pas une interface. – Jay

+0

Beaucoup de références données par Aaronaught finissent par utiliser des interfaces. Assez étonnamment Mono.Addins (http://www.mono-project.com/Mono.Addins) va la route d'attribut. – IAbstract

+0

C'est vrai, c'est pourquoi j'ai qualifié ma réponse à l'origine du mot "presque". ;) Il n'y a pas de réponse * right * ou * wrong * et vous pouvez même combiner les deux approches (utilisez les attributs pour trouver les classes tout en leur appliquant une interface plugin). – Aaronaught

Répondre

1

J'aurais probablement tendance à utiliser des attributs. L'extension du système de classes de base avec des métadonnées est exactement ce pour quoi elles sont destinées, et dire "cette classe est un plugin" correspond certainement à cette facture.

+0

@kyoryu: Je commence à pencher vers les attributs. Voir mon commentaire ci-dessus pour Mono.Addins. Je pense que c'est drôle - MS dit interface, Mono dit attributs. – IAbstract

1

Assembly.GetTypes est un appel très cher, et je l'éviterais si possible. (questions de temps de démarrage App)

L'un attribut de niveau d'assemblage plus rapide façon de le faire est probablement (je ne l'ai pas benchmarkée), qui serait utilisé comme ceci:

[assembly: PluginClass(typeof(MyPlugin), more info)] 

Vous pouvez ensuite appeler GetCustomAttributes sur le Assembly, ce qui serait probablement beaucoup plus rapide que GetTypes.

LINQ:

filenames.SelectMany(f => 
     Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true) 
     .Cast<PluginClassAttribute>() 
     .Select(a => a.PluginType) 
).ToList(); 
+0

Que se passe-t-il si une exception est levée pour l'un d'entre eux? –

+0

Ce Lambda est assez lourd ... –

+0

Si une exception se produit lors du chargement d'un assembly, l'appel 'ToList' sera lancé, et vous n'obtiendrez rien. Si vous voulez utiliser 'foreach' avec un bloc' catch', n'hésitez pas. – SLaks

2

Vous voulez que vos utilisateurs finaux pour écrire des plugins? Je ne pense pas que ce soit une très bonne idée, à moins que vos utilisateurs finaux soient des programmeurs.

Je vais garder ma réponse courte cette fois-ci puisque c'est un prettybighonkin'dupe:

  • architectures de plug-ins impliquent presque toujours des cours dans un ensemble externe mettant en œuvre une interface spécifique dans une commune Assemblée;

  • Il y a déjà dozens de cookie-cutter .NET plugin implémentations, y compris Microsoft propre Managed Extensibility Framework. Ne réinventez pas la roue.

Édition: Pour Mono, consultez Mono.Addins.

+0

Toutes mes excuses pour la jolie grande dupe. Je suppose que j'ai échoué à rechercher sur 'plugin'. ;/Anyhoo ... Je regarde les liens que vous avez fournis. – IAbstract

+0

@dboarman: Ne vous inquiétez pas, je voulais dire que ça a l'air léger, je suppose que c'est plutôt sarcastique. Je ne dénigre pas les downvotes ou quoi que ce soit d'autre, je voulais juste donner une raison claire à ma brève réponse et vous dire que c'est une exigence assez courante et qu'il y a beaucoup de bonnes ressources sur le sujet. – Aaronaught

+0

:) pas de soucis ... vous avez eu de bonnes références. Le seul problème est que MEF est disponible dans .NET 4.0 et puisque nous visons Mono, cela ne sera pas possible. BTW, +1 pour les grandes références !!! – IAbstract

Questions connexes