2010-08-17 52 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(); 
} 

我不明白;这只是简单的将类型转换为基本类型。我怎样才能解决这个问题?或任何替代品?

编辑:这里是什么LoadPluginAndCreateAnInstanceSomehow()做了总结:

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

编辑2:插件加载到另一个AppDomain中。我不得不在编译时添加IPlugin和ICustomPlugin.Definiton作为参考,因为应用程序必须知道CustomPlugin是什么样的。这是问题的根源吗?如果是这样,我该如何实现我想要做的?

编辑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 2010-08-18 02:19:36

+2

Assembly ass = Assembly.LoadFrom(fi.FullName)。大声笑在变量名称。 – obelix 2010-08-18 03:24:15

+1

我很困惑。为什么有人预期从不同应用程序域加载的类型将与当前应用程序域中加载的相同类型兼容? – 2010-08-18 03:28:21

回答

2

我设法重现了这个问题。考虑以下。

假设你的项目有以下运行时的结构(简化当然)

C:\运行\ - 这是你的主要运行时目录,有主机。EXE
C:\运行\图书馆\ - 该路径有你的三个库组件

的EXE项目引用定义接口的两个组件,所以它们复制到运行文件夹,但不引用组件包含CustomPlugin,因此不会被复制。

如果项目DID的旧版本引用CustomPlugin.dll并将旧版本复制到\ Runtime会怎么样?然后你分开这些。新版本不再被复制,但旧版本仍然存在。

因此,当您从App库中的AppDomain中创建类时,一切正常,但是当编组回到AppDomain边界时,主AppDomain需要加载匹配程序集以获取类型信息。它首先找到旧版本。如果旧版本未实现ICustomConfig,则投射将失败。你之前提到过他们没有签名,所以.NET会为你犯这个错误没有问题!

所以你的运行目录包含

Host.exe
BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - 不执行ICustomPlugin

而且你的图书馆目录旧版本包含

BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - 新版本

编辑

你可以随时检查Assembly.Location的plugin.GetType()的值,看看哪些dll被加载在每个AppDomain中。

+0

我删除了所有东西(bin,lib,tmp.obj等),并从头开始构建解决方案,所以不会有任何旧版本/新版本的问题。我正在加载到CurrentAppDomain的插件。问题仍然存在:/ – Slantroph 2010-08-18 07:31:58

+0

您是否尝试查看每个插件的plugin.GetType()。Assembly.Location? – Sam 2010-08-18 23:16:38

+0

我将引用的“Copy Local”属性设置为false。现在它就像一个魅力,谢谢! – Slantroph 2010-08-19 02:29:08

1

我不能肯定这是为什么发生的,但使用铸造的“作为”型,当你没有得到任何信息当演员失败。

MSDN文档说: “as运算符类似于转换操作;但是,如果转换不可行,返回null而不是引发异常。

所以请尝试使用:

ICustomPlugin customPlugin = (ICustomPlugin)plugin; 

,看看是否存在异常的一些信息,可以帮助解释为什么。

+0

“无法将'CustomPlugin'类型的对象转换为'ICustomPlugin'” – Slantroph 2010-08-17 23:55:25

0

我怀疑这里有两种不同的ICustomPlugin类型。例如,如果您正在执行强名称签名,并且CustomPlugin.dll加载的HostPlugin.Definition.dll的版本不同于Host.exe加载的版本,则这是可能的。

+0

dll未签名。并且它们从相同的文件夹加载相同的dll。 – Slantroph 2010-08-18 00:10:11

+1

我同意,这一行非常相关:plugin = LoadPluginAndCreateAnInstanceSomehow();请分享该方法正在做的事情。 – 2010-08-18 00:12:18

+1

当您在Host.exe中对Customoflugin.dll进行评估时,获得的typeof(ICustomPlugin).AssemblyQualifiedName是什么? – 2010-08-18 00:17:02

相关问题