2010-08-17 7 views
5

J'ai un problème pour lancer un objet sur l'une des interfaces de base d'une autre bibliothèque. Voici le code correspondant:Transférer un objet à l'interface de base

BaseSDK.dll

public interface IPlugin 
{ 
    void Run(); 
} 

CustomPlugin.Definition.dll:

public interface ICustomPlugin 
{ 
    void DoCustomStuff(); 
} 

CustomPlugin.dll (a référence à BaseSDK.dll et CustomPlugin.Definition.dll):

public class CustomPlugin: IPlugin, ICustomPlugin 
{ 
    public void Run() 
    { 

    } 

    public void DoCustomStuff() 
    { 

    } 
} 

host.exe (a des références à BaseSDK.dll et CustomPlugin.Definition.dll):

IPlugin plugin; 
public void DoStuff() 
{ 
    plugin = LoadPluginAndCreateAnInstanceSomehow(); 
    // I know plugin is a CustomPlugin 
    ICustomPlugin customPlugin = plugin as ICustomPlugin; //cast fails. 
    customPlugin.DoCustomStuff(); 
} 

Je ne comprends pas; c'est juste type-cast un type à son type de base. Comment puis-je réparer cela? ou des alternatives?

Edit: Voici un résumé de ce LoadPluginAndCreateAnInstanceSomehow() fait:

Assembly ass = Assembly.LoadFrom(filename); 
Type t = ass.GetType(ass.FullName + ".CustomPlugin"); 
plugin = (IPlugin)Activator.CreateInstance(t); 

Edit 2: Plugins sont chargés dans un autre AppDomain. J'ai dû ajouter IPlugin et ICustomPlugin.Definiton comme référence à la compilation car l'application doit avoir une idée de ce qu'est un CustomPlugin. Est-ce la source du problème? si oui, comment puis-je réaliser ce que j'essaie de faire?

Edit 3: Plugins sont chargés comme ceci:

public class PluginLoader 
    { 
     List<IPlugin> Plugins; 
     AppDomain Domain; 
     string libPath; 
     public void PluginLoader(string sLibPath, AppDomain sDomain) 
     { 

      libPath = sLibPath; 
      Plugins = new List<IPlugin>(); 
      Domain = sDomain; 
      if(Domain==null)Domain = AppDomain.CreateDomain("PluginsDomain"); 
      Domain.AssemblyResolve += new ResolveEventHandler(Domain_AssemblyResolve); 
      Domain.TypeResolve += new ResolveEventHandler(Domain_TypeResolve); 
      Domain.DoCallBack(new CrossAppDomainDelegate(DomainCallback)); 
     } 

     Assembly Domain_AssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      return Assembly.LoadFrom(args.Name); 
     } 
     Assembly Domain_TypeResolve(object sender, ResolveEventArgs args) 
     { 
      return Assembly.LoadFrom(args.Name); 
     } 
     void DomainCallback() 
     { 
      string[] fileNames = Directory.GetFiles(libPath, "*.dll"); 
      foreach (string filename in fileNames) 
      { 

       FileInfo fi = new FileInfo(filename); 
       Assembly ass = Assembly.LoadFrom(fi.FullName); 
       Type t = ass.GetType(ass.FullName + ".CustomPlugin"); 
       IPlugin p = (IPlugin)Activator.CreateInstance(t); 
       Plugins.Add(p); 
      } 
     } 
    }
+1

Pouvez-vous nous montrer comment vous chargez le plug-in dans un autre AppDomain? J'ai essayé ceci avec la DLL dans différents endroits, mais je ne peux pas reproduire votre problème. – Sam

+2

Assemblage ass = Assembly.LoadFrom (fi.FullName). lol au nom de la variable. – obelix

+1

Je suis confus. Pourquoi s'attend-on à ce que les types chargés à partir d'un autre domaine d'application soient compatibles avec les mêmes types chargés dans le domaine d'application actuel? –

Répondre

2

J'ai réussi à reproduire ce problème. Considérer ce qui suit.

Supposons que votre projet a la structure d'exécution suivante (simplifiée bien sûr)

C: \ Runtime \ - c'est votre répertoire principal d'exécution et a l'hôte.exe
C: \ Runtime \ Library \ - ce chemin a vos trois ensembles de bibliothèque

Le projet exe fait référence aux deux ensembles qui définissent l'interface, de sorte qu'ils sont copiés dans le dossier d'exécution, mais ne fait pas référence à l'assemblage contient CustomPlugin, donc il n'est pas copié.

Que se passerait-il si une ancienne version du projet DID faisait référence à CustomPlugin.dll et copiait une ancienne version dans \ Runtime? Ensuite, plus tard, vous les avez séparés. La nouvelle version n'est plus copiée, mais l'ancienne version reste. Ainsi, lorsque vous créez la classe dans AppDomain à partir de \ Library, tout va bien, mais lorsque vous revenez sur la limite AppDomain, le domaine principal AppDomain doit charger l'assembly correspondant pour obtenir les informations de type. Il trouve l'ancienne version en premier. Si l'ancienne version n'implémente pas ICustomConfig, la distribution échouera. Vous avez mentionné plus tôt qu'ils ne sont pas signés, donc .NET n'aurait aucun problème à faire cette erreur pour vous!

donc votre répertoire d'exécution contient

host.exe
BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - ancienne version non mise en œuvre ICustomPlugin

Et votre répertoire de la bibliothèque contient

BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll -. Nouvelle version

EDIT

Vous pouvez toujours vérifier la valeur de plugin.GetType() Assembly.Location pour voir qui dll son chargement dans chaque AppDomain.

+0

J'ai tout supprimé (bin, lib, tmp, obj, etc ..) et construit la solution à partir du zéro, donc il n'y aurait pas de problème de version ancienne/nouvelle. Je charge des plugins dans CurrentAppDomain, le problème est toujours là:/ – Slantroph

+0

Avez-vous essayé de regarder plugin.GetType(). Assembly.Location pour chaque plugin? – Sam

+0

J'ai défini les propriétés "Copy Local" des références sur false. chemins et maintenant cela fonctionne comme un charme. – Slantroph

1

Je ne suis pas certain de savoir pourquoi cela se produit, mais lorsque vous utilisez le « comme » type de coulée ne vous reçois pas d'informations quand la distribution échoue. La documentation MSDN dit: "L'opérateur as est similaire à une opération de distribution, mais si la conversion n'est pas possible, renvoie null au lieu de déclencher une exception."

Donc, essayez en utilisant:

ICustomPlugin customPlugin = (ICustomPlugin)plugin; 

et voir s'il y a des informations à l'exception qui peut aider à expliquer pourquoi.

+0

"Impossible de convertir l'objet de type 'CustomPlugin' en 'ICustomPlugin'" – Slantroph

0

Je suppose qu'il y a deux types ICustomPlugin différents en jeu ici. Cela est possible, par exemple, si vous effectuez une signature de nom fort, et CustomPlugin.dll charge une version différente de CustomPlugin.Definition.dll que Host.exe est en cours de chargement.

+0

Les DLL ne sont pas signées. et ils chargent la même DLL à partir du même dossier. – Slantroph

+1

Je suis d'accord, cette ligne est très pertinente: plugin = LoadPluginAndCreateAnInstanceSomehow(); S'il vous plaît partagez ce que cette méthode est en train de faire. –

+1

Qu'est-ce que vous obtenez pour 'typeof (ICustomPlugin) .AssemblyQualifiedName' lorsqu'il est évalué dans Host.exe par rapport à CustomPlugin.dll? –

Questions connexes