10

我正试图围绕反射来思考,所以我决定将插件功能添加到我正在编写的程序中。理解一个概念的唯一方法就是动手编写代码,所以我创建了一个由 IPlugin 和 IHost 接口组成的简单接口库,一个实现 IPlugin 的类的插件实现库,以及一个简单的实例化 IHost 实现类的控制台项目,该类对插件对象进行简单的工作。

使用反射,我想遍历我的插件实现 dll 中包含的类型并创建类型的实例。我能够使用此代码成功实例化类,但我无法将创建的对象强制转换为接口。

我尝试了这段代码,但我无法按预期投射 object o。我使用调试器逐步完成了该过程,并调用了正确的构造函数。Quickwatching 对象 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();

以下是我的问题:

  1. Activator.CreateInstance(Type t) 返回一个对象,但我无法将该对象转换为该对象实现的接口。为什么?
  2. 我应该使用不同的 CreateInstance() 重载吗?
  3. 反射相关的提示和技巧是什么?
  4. 是否有一些我没有得到的反思的关键部分?
4

7 回答 7

4

我只是在这里猜测,因为从您的代码来看,您在哪里定义 IPlugin 接口并不明显,但是如果您不能在主机应用程序中进行转换,那么您可能在主机程序集中有 IPlugin 接口,然后同时在你的插件程序集。这行不通。

最简单的方法是让 IPlugin 接口在您的主机程序集中标记为公共,然后让您的插件程序集引用主机应用程序程序集,这样两个程序集都可以访问相同的接口

于 2008-08-28T03:46:33.257 回答
2

嗯...如果您使用 Assembly.LoadFrom 加载程序集,请尝试更改它 Assembly.LoadFile。

为我工作

从这里:http ://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

于 2008-10-07T12:52:14.350 回答
1

@lubos哈斯科

你把它钉在鼻子上。我的原始设计确实有三个不同的程序集,其中主机和插件实现都引用了插件接口程序集。

我尝试了一个带有主机实现和接口程序集以及插件实现程序集的单独解决方案。在该解决方案中,第一个块中的代码按预期工作。

你给了我更多的思考,因为我不太明白为什么引用一个公共程序集的两个程序集不会从公共程序集中得到相同的类型。

于 2008-08-28T23:47:08.283 回答
1

我只是想自己解决这个问题并设法偶然发现了答案!

我有 3 个不同的 C# 项目

  • A - 插件接口项目
  • B - 宿主 exe 项目 -> 引用 A
  • C - 插件实现项目 -> 参考 A

在我更改插件接口项目的程序集名称以匹配我尝试转换的名称空间之前,我也遇到了转换错误。

例如

IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);

失败是因为定义 IPluginModule 接口的程序集被称为“Common”,但是我正在转换的 -type- 是“Blah.Plugins.Common.IPluginModule”。

我将接口项目的程序集名称更改为“Blah.Plugins.Common”,这意味着转换成功。

希望这个解释对某人有所帮助。回到代码..

于 2008-10-07T12:26:48.083 回答
0

您的类型是否不公开,如果是,请调用接受布尔值的重载:

Activator.CreateInstance(type, true);

此外,在您的第一个示例中,查看 o 是否为空,如果不是,则打印出 o.GetType().Name 以查看它的真正含义。

于 2008-08-28T02:57:30.440 回答
0

@哈克德

我试图保持伪代码简单。foreach 占用大量空间和大括号。我澄清了。

o.GetType().FullName 返回 Plugins.Multiply 这是预期的对象。Plugins.Multiply 实现了 IPlugin。我在调试器中多次执行该过程,直到我放弃了晚上。无法弄清楚为什么我不能施放它,因为我看着构造函数开火,直到我对整个混乱局面感到脾气暴躁。今天晚上回来让它工作,但我仍然不明白为什么演员在第一个代码块中失败了。第二个代码块有效,但对我来说感觉不对。

于 2008-08-28T03:35:46.557 回答
0

上面的蛋头链接是使用 Assembly.LoadFile() 而不是 .LoadFrom() 问题的主要解决方案

于 2011-01-26T18:45:15.087 回答