Question

J'essaie de comprendre la réflexion, j'ai donc décidé d'ajouter une fonctionnalité de plugin à un programme que j'écris.La seule façon de comprendre un concept est de se salir les doigts et d'écrire le code. J'ai donc choisi de créer une bibliothèque d'interface simple composée des interfaces IPlugin et IHost, une bibliothèque d'implémentation de plugin de classes qui implémentent IPlugin et un simple projet de console qui instancie la classe d'implémentation IHost qui effectue un travail simple avec les objets plugin.

En utilisant la réflexion, je voulais parcourir les types contenus dans la DLL d’implémentation de mon plugin et créer des instances de types.J'ai réussi à instancier des classes avec ce code, mais je n'ai pas pu convertir l'objet créé vers l'interface.

J'ai essayé ce code mais je n'ai pas pu lancer l'objet o comme je m'y attendais.J'ai suivi le processus avec le débogueur et le constructeur approprié a été appelé.L'objet Quickwatching o m'a montré qu'il possédait les champs et les propriétés que je m'attendais à voir dans la classe d'implémentation.

loop through assemblies
  loop through types in assembly
    // Filter out unwanted types
    if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
      continue;
    // This successfully created the right object
    object o = Activator.CreateInstance(type);
    // This threw an Invalid Cast Exception or returned null for an "as" cast
    // even though the object implemented IPlugin      
    IPlugin i = (IPlugin) o;

J'ai fait fonctionner le code avec ça.

using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();

Voici mes questions :

  1. Activator.CreateInstance(Type t) renvoie un objet, mais je n'ai pas pu convertir l'objet en une interface implémentée par l'objet.Pourquoi?
  2. Aurais-je dû utiliser une surcharge différente de CreateInstance() ?
  3. Quels sont les trucs et astuces liés à la réflexion ?
  4. Y a-t-il une partie cruciale de la réflexion que je ne comprends tout simplement pas ?
Était-ce utile?

La solution

Je suppose juste ici parce que d'après votre code, il n'est pas évident où avez-vous la définition de l'interface IPlugin, mais si vous ne pouvez pas diffuser votre application hôte, vous avez probablement l'interface IPlugin dans votre assembly hôte, puis en même temps dans votre assemblage de plugin.Cela ne fonctionnera pas.

La chose la plus simple pour que cela fonctionne est d'avoir l'interface IPlugin marquée comme publique dans votre assembly hôte, puis d'avoir votre assembly Plugin assemblage d'application hôte de référence, les deux assemblées ont donc accès à la même interface.

Autres conseils

hmmm...Si vous utilisez Assembly.LoadFrom pour charger votre assembly, essayez plutôt de le modifier Assembly.LoadFile.

A travaillé pour moi

D'ici: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

@Lubos Hasko

Vous l'avez cloué sur le nez.Ma conception originale comportait trois assemblages différents, l'implémentation de l'hôte et du plugin faisant référence à l'assemblage de l'interface du plugin.

J'ai essayé une solution distincte avec une implémentation hôte et un assemblage d'interface ainsi qu'un assemblage d'implémentation de plugin.Dans cette solution, le code du premier bloc a fonctionné comme prévu.

Vous m'avez donné un peu plus de matière à réflexion, car je ne comprends pas très bien pourquoi deux assemblys faisant référence à un assembly commun n'obtiennent pas le même type de l'assembly commun.

J'essayais juste de résoudre ce problème moi-même et j'ai réussi à trouver la réponse !

J'ai eu 3 projets C# différents

  • A - Projet d'interface de plugin
  • B - Projet exe hôte -> références A
  • C - Projet d'implémentation de plugin -> références A

J'obtenais également l'erreur de diffusion jusqu'à ce que je change le nom de l'assembly de mon projet Plugin Interface pour qu'il corresponde à l'espace de noms de ce que j'essayais de diffuser.

Par exemple.

IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);

échouait parce que l'assembly dans lequel l'interface IPluginModule était définie s'appelait "Common". Le -type- vers lequel je diffusais était cependant "Blah.Plugins.Common.IPluginModule".

J'ai changé le nom de l'assembly pour le projet d'interface en « Blah.Plugins.Common », ce qui signifie que le casting a ensuite réussi.

J'espère que cette explication aidera quelqu'un.Revenons au code..

Votre type n'est-il pas public, si c'est le cas, appelez la surcharge qui prend un booléen :

Activator.CreateInstance(type, true);

De plus, dans votre premier exemple, voyez si o est nul et sinon, imprimez o.GetType().Name pour voir ce que c'est réellement.

@Haacké

J'ai essayé de garder le pseudocode simple.les foreach prennent beaucoup de place et d'accolades.Je l'ai clarifié.

o.GetType().FullName renvoie Plugins.Multiply qui est l'objet attendu.Plugins.Multiply implémente IPlugin.J'ai parcouru le processus dans le débogueur plusieurs fois jusqu'à ce que j'abandonne pour la soirée.Je n'arrivais pas à comprendre pourquoi je ne pouvais pas le lancer parce que j'avais regardé le constructeur tirer jusqu'à ce que je devienne grincheux à cause de tout ce désordre.J'y suis revenu ce soir et je l'ai fait fonctionner, mais je ne comprends toujours pas pourquoi le casting a échoué dans le premier bloc de code.Le deuxième bloc de code fonctionne, mais cela me dérange.

Le lien vers Egghead ci-dessus est la principale solution au problème, utilisez Assembly.LoadFile() au lieu de .LoadFrom()

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top