.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-time
, interface casting
将像您的示例一样失败(C#将我们的接口知道为与该类inheritance的类型不同的类型)。
在这种情况下,这是我简单实用的技巧:
当我确定我的Class
inheritance了上面提到的Interface
( IFrameworkClient
)时,我写了一行神奇的代码 :
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