题
我正在尝试思考反射,因此我决定向我正在编写的程序添加插件功能。理解概念的唯一方法就是亲自动手编写代码,因此我创建了一个简单的接口库,其中包含 IPlugin 和 IHost 接口、实现 IPlugin 的类的插件实现库以及一个简单的接口库。实例化 IHost 实现类的控制台项目,该实现类对插件对象进行简单的工作。
使用反射,我想迭代插件实现 dll 中包含的类型并创建类型的实例。我能够使用此代码成功实例化类,但无法将创建的对象转换为接口。
我尝试了这段代码,但无法按我的预期投射对象 o 。我使用调试器逐步完成了该过程,并调用了正确的构造函数。快速观察对象 o 向我展示了它具有我期望在实现类中看到的字段和属性。
loop through assemblies
loop through types in assembly
// Filter out unwanted types
if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
continue;
// This successfully created the right object
object o = Activator.CreateInstance(type);
// This threw an Invalid Cast Exception or returned null for an "as" cast
// even though the object implemented IPlugin
IPlugin i = (IPlugin) o;
我让代码与此一起工作。
using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();
这是我的问题:
- Activator.CreateInstance(Type t) 返回一个对象,但我无法将该对象转换为该对象实现的接口。为什么?
- 我应该使用不同的 CreateInstance() 重载吗?
- 与反射相关的提示和技巧有哪些?
- 是否有一些我没有得到反思的关键部分?
解决方案
我只是在这里猜测,因为从您的代码来看,您在哪里定义 IPlugin 接口并不明显,但如果您无法在主机应用程序中进行强制转换,那么您可能在主机程序集中有 IPlugin 接口,然后同时在你的插件程序集。这行不通。
最简单的方法是在主机程序集中将 IPlugin 接口标记为公共,然后让您的插件程序集工作 参考主机应用程序集, ,因此两个程序集都可以访问 完全相同的界面.
其他提示
嗯...如果您使用 Assembly.LoadFrom 加载程序集,请尝试将其更改为 Assembly.LoadFile。
为我工作
从这里: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx
你把它钉在鼻子上了。我的原始设计确实具有三个不同的程序集,其中主机和插件实现都引用插件接口程序集。
我尝试了一个单独的解决方案,其中包含主机实现和接口程序集以及插件实现程序集。在该解决方案中,第一个块中的代码按预期工作。
您给了我更多的思考空间,因为我不太明白为什么引用公共程序集的两个程序集不能从公共程序集中获得相同的类型。
我只是想自己解决这个问题并偶然发现了答案!
我有 3 个不同的 C# 项目
- A - 插件接口项目
- B - 宿主 exe 项目 -> 引用 A
- C - 插件实现项目 -> 参考文献 A
我也遇到了转换错误,直到我更改了插件接口项目的程序集名称以匹配我尝试转换的名称空间。
例如。
IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);
失败是因为定义 IPluginModule 接口的程序集被称为“Common”,但是我要转换的类型是“Blah.Plugins.Common.IPluginModule”。
我将接口项目的程序集名称更改为“Blah.Plugins.Common”,这意味着转换成功。
希望这个解释对某人有所帮助。回到代码..
您的类型是否不是公开的,如果是,请调用接受布尔值的重载:
Activator.CreateInstance(type, true);
另外,在第一个示例中,查看 o 是否为 null,如果不是,则打印出 o.GetType().Name 以查看它到底是什么。
我试图让伪代码保持简单。foreach 占用了大量空间和大括号。我澄清了。
o.GetType().FullName 返回 Plugins.Multiply,这是预期的对象。Plugins.Multiply 实现 IPlugin。我在调试器中单步执行了这个过程好几次,直到晚上我放弃了。不明白为什么我不能投射它,因为我看着构造函数火了,直到我对整个混乱感到脾气暴躁。今天晚上回来并使其工作,但我仍然不明白为什么第一个代码块中的转换失败。第二个代码块有效,但我感觉不太好。
上面蛋头的链接是使用 Assembly.LoadFile() 而不是 .LoadFrom() 问题的主要解决方案