【问题标题】:How to properly cast objects created through reflection如何正确投射通过反射创建的对象
【发布时间】:2008-08-28 02:50:55
【问题描述】:

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

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

我尝试了这段代码,但无法按预期转换对象 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. 是否有一些我没有得到的反射的关键部分?

【问题讨论】:

    标签: c# .net reflection


    【解决方案1】:

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

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

    【讨论】:

    • 对于一个简单的应用程序来说可能有点矫枉过正,但另一种方法是创建一个单独的库,其中只包含接口并从所有需要了解的信息中引用它:o)
    【解决方案2】:

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

    为我工作

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

    【讨论】:

    • 我遇到了与这里描述的相同的问题。更改为 Assembly.LoadFile 为我解决了这个问题。
    【解决方案3】:

    @lubos hasko

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

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

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

    【讨论】:

      【解决方案4】:

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

      我有 3 个不同的 C# 项目

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

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

      例如

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

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

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

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

      【讨论】:

        【解决方案5】:

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

        Activator.CreateInstance(type, true);
        

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

        【讨论】:

          【解决方案6】:

          @Haacked

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

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-09-11
              • 1970-01-01
              • 1970-01-01
              • 2023-04-05
              • 2011-03-02
              • 2022-12-07
              • 1970-01-01
              相关资源
              最近更新 更多