2010-08-17 4 views
5

У меня возникла проблема с литьем объекта на один из его базовых интерфейсов, живущих в другой библиотеке. Вот код для этого:литье объекта в базовый интерфейс

BaseSDK.dll

public interface IPlugin 
{ 
    void Run(); 
} 

CustomPlugin.Definition.dll:

public interface ICustomPlugin 
{ 
    void DoCustomStuff(); 
} 

CustomPlugin.dll (имеет отношение к BaseSDK.dll и CustomPlugin.Definition.dll):

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

    } 

    public void DoCustomStuff() 
    { 

    } 
} 

host.exe (имеет ссылки на BaseSDK.dll и 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(); 
} 

Я не понимаю; это простой тип, накладывающий тип на его базовый тип. Как я могу это исправить? или какие-либо альтернативы?

Edit: Вот краткое изложение того, что LoadPluginAndCreateAnInstanceSomehow() делает:

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

Edit 2: Плагины загружаются в другой AppDomain. Я должен был добавить IPlugin и ICustomPlugin.Definiton в качестве ссылки во время компиляции, потому что приложение должно иметь представление о том, что такое CustomPlugin. это источник проблемы? если да, то как я могу достичь того, что я пытаюсь сделать?

Edit 3: Плагины загружаются так:

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

Можете ли вы показать нам, как вы загружаете плагин в другой AppDomain? Я пробовал это с dll в разных местах, но я не могу повторить вашу проблему. – Sam

+2

Assembly ass = Assembly.LoadFrom (fi.FullName). lol при имени переменной. – obelix

+1

Я в замешательстве. Почему существует ожидание того, что типы, загруженные из другого домена приложения, будут совместимы с теми же типами, которые загружаются в текущий домен приложения? –

ответ

2

Мне удалось воспроизвести эту проблему. Рассмотрим следующее.

Предположим, ваш проект имеет следующую структуру выполнения (упрощенный конечно)

C: \ Продолжительность \ - это ваш основной каталог выполнения и имеет хост.ехе
C: \ Продолжительность \ Library \ - этот путь имеет свои три библиотеки сборки

Проект ехе ссылается на два узла, которые определяют интерфейс, таким образом, они копируются в папку во время выполнения, но не ссылается на сборку, содержит CustomPlugin, поэтому он не копируется.

Что делать, если старшая версия проекта DID ссылается на CustomPlugin.dll и скопировала старую версию в \ Runtime? Затем вы разделили их. Новая версия больше не копируется, но старая версия остается.

Итак, когда вы создаете класс в AppDomain из \ Library, все в порядке, но при переходе по границе AppDomain основной AppDomain необходимо загрузить соответствующую сборку, чтобы получить информацию о типе. Сначала он находит старую версию. Если старая версия не реализует ICustomConfig, то приведение не будет выполнено. Вы упомянули ранее, что они не подписаны, поэтому у .NET не возникнет проблем с этой ошибкой!

Так ваш каталог среда содержит

host.exe
BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - старая версия не реализует ICustomPlugin

И ваш библиотечный каталог содержит

BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll. - новая версия

EDIT

Вы всегда можете проверить значение plugin.GetType() Assembly.Location, чтобы увидеть, какие библиотеки DLL она загружается в каждом AppDomain.

+0

Я удалил все (bin, lib, tmp. Obj и т. Д.) И построил решение с нуля, поэтому не было никакой проблемы с старой/новой версией. Я загружаю плагины в CurrentAppDomain. Проблема все еще есть:/ – Slantroph

+0

Попробовал ли вы посмотреть на plugin.GetType(). Assembly.Location для каждого плагина? – Sam

+0

Я установил свойства «Copy Local» ссылок на false. пути, и теперь это работает как шарм. спасибо! – Slantroph

1

Я не уверен, почему это происходит, но при использовании «как» тип литья вы не получаете никакой информации когда сбой происходит.

В документации MSDN указано: «Оператор as похож на операцию литья, однако, если преобразование невозможно, поскольку возвращает значение null вместо воссоздания исключения».

Так попробуйте использовать:

ICustomPlugin customPlugin = (ICustomPlugin)plugin; 

и посмотреть, если есть какая-то информация в исключение, которое может помочь объяснить, почему.

+0

«Невозможно наложить объект типа« CustomPlugin »на« ICustomPlugin »« – Slantroph

0

Я подозреваю, что здесь есть два разных типа ICustomPlugin. Это возможно, например, если вы подписываете сильное имя, а CustomPlugin.dll загружает другую версию CustomPlugin.Definition.dll, чем загружается Host.exe.

+0

DLL не подписаны. и они загружают одну и ту же DLL из той же папки. – Slantroph

+1

Согласен, эта строка очень актуальна: plugin = LoadPluginAndCreateAnInstanceSomehow(); Пожалуйста, поделитесь тем, что делает этот метод. –

+1

Что вы получаете для 'typeof (ICustomPlugin) .AssemblyQualifiedName' при оценке в Host.exe по сравнению с CustomPlugin.dll? –

Смежные вопросы