.NET:无法将对象强制转换为它实现的接口

我有一个类(TabControlH60),它inheritance自基类(UserControl)并实现一个接口(IFrameworkClient)。 我使用.NET Activator类实例化对象。 使用返回的实例,我可以转换为UserControl基类,但不能转换为接口。 我得到的例外是在代码snipet下面。 如何投射界面?

object obj = Activator.CreateInstance(objType); Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient m_Client = (UserControl)obj; // base class cast works IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails // Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window. {"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 'FPG.AFF.Interfaces.IFrameworkClient'."} 

我遇到了同样的问题,我的库提供了“插件”function……我终于让它工作了……

这是我的问题:我有一个主要程序集使用插件,一个程序集与插件(Plugin.dll)和(重要)另一个程序集提供插件function(Library.dll)。

Plugin.dll引用了主程序集(为了能够扩展它)和带有plugin-func的Library.dll。 – 它的二进制文件到达相对于主程序集的目录“./Plugins”。

主程序集还引用了plugin-func。 汇编为了使用“PluginManager”写的。 这个“PluginManager”获取一个路径,并通过reflection加载所有* .dll文件,以分析是否存在“IPlugin”接口(也来自Library.dll)。

我每次调用PluginManager加载插件时都无法将它们转换为“IPlugin”,尽管它们实现了它。

我几乎生气了 – 但后来我发现了整个问题。 通过编译插件,不仅有“Plugin.dll”,而且“Library.dll”写入“./Plugins”目录。 每次使用我的PluginManager意外加载“Library.dll”时,我现在有两种类型的“IPlugin” – 一个在主程序集中使用的实际“Library.dll”中,另一个是通过我的PluginManager加载的 – 那些是不相容的!

注意 – 如果你只是不加载“./Plugins/Library.dll”你仍然遇到问题 – 因为如果你加载“Plugin.dll”引用“Library.dll”,那么它只是使用同一目录中的那个。 ..倾斜…… !! 我的PluginManager现在只删除它找到它的“Library.dll”。

线索是:确保您不会在不同的上下文中访问两个程序集!

这里最可能的原因是IFrameworkClient来自两种情况下的不同程序集,因此是不同的.NET类型。 即使它是相同的代码,它也可以是不同的类型。

检查AssemblyQualifiedName 。 另请注意,如果使用reflection加载此程序集,则即使使用相同的AssemblyQualifiedName也可以获得不同的类型,这要归功于load-context。

独立项目(类库)的独立命名空间(必须具有命名空间)中定义IFrameworkClient接口。然后将类库的参考添加到Control项目和主项目

有些东西告诉我你的示例代码留下了一些东西……

 class Program { static void Main(string[] args) { var type = typeof(MyClass); object obj = Activator.CreateInstance(type); Type[] interfaces = obj.GetType().GetInterfaces(); var m_Client = (UserControl)obj; IFrameworkClient fc = (IFrameworkClient)obj; } } public interface IFrameworkClient { } public class UserControl { } public class MyClass : UserControl, IFrameworkClient { } 

这编译并运行。

我打赌在尝试强制转换之前,尚未加载包含IFrameworkClient定义的DLL。 当您使用Activator.CreateInstance时,可能会发生这种情况。

尝试插入var forceLoad = typeof(IFrameworkClient); 演员之前。

Interface 在不同的程序集中并且我在不同的程序集中在run-time 动态获取我的类run-timeinterface casting将像您的示例一样失败(C#将我们的接口知道为与该类inheritance的类型不同的类型)。

在这种情况下,这是我简单实用的技巧:

当我确定我的Classinheritance了上面提到的InterfaceIFrameworkClient )时,我写了一行神奇的代码

 dynamic fc = obj as IFrameworkClient ?? (dynamic) obj; 

通过这种技术,您可以:

  • design time根据Interface members信息和编辑器智能系统在fc这行代码之后编写代码。
  • run-time防止任何接口转换错误

笔记:

  • 您需要C# v4才能使用dynamic类型
  • 通常我不喜欢在我的代码中使用dynamic类型,但在某些情况下它可以帮助我们

如果类FPG.H60​​.AFF.TabControlH60实际上实现了IFrameworkClient,则应该没有理由这会失败。 我唯一能想到的是导致此exception的原因是,包含IFrameworkClient的程序集是强命名的,并且Tab Control对象恰好引用了包含程序集的不同版本,或者您正在使用名为IFrameworkClient的其他接口。

在我的情况下,我必须添加一个构建事件来复制所需的DLL,因为我在运行时创建实例并分配给接口类型。 否则,加载的DLL可能不是最新的DLL,因此可能不会强制转换为接口。

我在这种情况下使用构建事件(而不是添加DLL作为引用)的原因是该体系结构使得主应用程序应该仅引用接口类型,并且其他所有内容都应该动态加载。

TLDR; 在从另一个DLL动态加载类型的情况下,请确保使用构建事件将该DLL的最新版本复制到bin目录,否则当它应该出现时,强制转换可能不起作用。

由于您正在尝试从类型object转换为接口,因此强制转换无效。 如果用以下代码替换界面强制线:

IFrameworkClient fc = (IFrameworkClient)m_Client;

它会工作。

或者,我有点确定你可以使用as运算符从对象到接口进行转换。

有关更多信息,请参阅此文章: http : //blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

还有一块拼图。 接口不是从object派生的: http : //blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx