【问题标题】:Interfaces and Late Binding in C#C# 中的接口和后期绑定
【发布时间】:2012-11-21 05:38:06
【问题描述】:

我之前在 C# 中为一个运行良好的插件系统做过这个,这就是为什么我不明白为什么这个新的、独立的插件系统不能按我预期的方式运行。

我有我的插件程序集——我们称之为“plugin.dll”,我有我的主程序集——我们称之为 App.exe。

我有一个名为IMyObject 的接口及其实现MyObject,两者都在plugin.dll 中定义。我已将 IMyObject(插件开发人员提供给我)的确切代码文件复制到我的主 App.exe 程序集中。

当我尝试将使用反射加载的对象投射到对象实现的接口时,我得到一个InvalidCastException。我知道对象实现了它,因为

t.GetInterface(typeof(IMyObject).FullName) != null

是真的。我也可以在 Visual Studio 的对象资源管理器中浏览MyObject,我可以看到它实现了IMyObject

这里出了问题:

 if (ifaceType != null)
 {
    ConstructorInfo constructor = ifaceType.GetConstructor(new Type[] { });

    if (constructor != null)
    {

       object obj = constructor.Invoke(null); // this works - obj is assigned an 
                                              // instance of MyObject

       IMyObject myObj = (IMyObject)obj;      // triggers InvalidCastException
    }               
 }

我现在所做的与我之前实现的方式之间唯一的区别是接口是在两个单独的程序集中定义的(即使代码文件相同并且它们属于同一个命名空间)。

这就是我麻烦的原因吗?如果是这样,我怎样才能连接到我的插件而不在编译时链接,并使用插件本身定义的接口?

除了界面之外,我应该补充一点,我无法访问插件的源代码。

【问题讨论】:

  • 您是否考虑过可以同时引用的第三个程序集?我不能 100% 确定您尝试做的事情会“正常工作”。
  • 这就是我以前做过一次的方式并且有效,但是这一次,情况是我无法访问除接口本身之外的插件代码。
  • 你说的没有任何意义。您不需要访问插件代码。您公开一个接口并从程序集中加载实现该接口的类型。然后您针对接口调用函数..这如何转换为“您需要访问插件代码”..?
  • 我不是说难。如果我可以访问代码,我确实可以添加一个公共的第三个程序集,并且我的主程序集和插件都可以引用该公共程序集。正如我所说,我无权访问插件代码,因此无法自己编译插件。
  • 那么,您试图通过复制该程序集中的接口并动态加载它来从另一个程序集中加载一段代码?你怎么知道这个接口存在于另一个程序集中?

标签: c# plugins interface late-binding .net


【解决方案1】:

即使这些接口具有相同的代码,它们也是两个不同程序集中的两个独立接口(您可以打印它们的 AssemblyQualifiedNames 并查看差异)。

【讨论】:

  • 如果我用它,它不会是一个后期绑定插件吧?
  • 对不起,错过了标题中的那篇文章。确实没有办法在运行时加载类型(即接口)并以强(静态)类型的方式使用它。您可以使用通用接口库或仅使用 dynamic 代替接口。
  • dynamic 不是一个选项,因为我们都在使用 .Net 2.0。看起来我将不得不向插件开发人员提供一个 DLL,该 DLL 具有 I 定义并且我们都引用的接口。
【解决方案2】:

是的,运行时将接口视为不同的类型。它们的名字相同。

没有反射就没有办法在宿主程序中使用接口,因为你不能静态链接它。通常,将接口放在插件宿主程序集中并由插件实现它们,而不是相反。

【讨论】:

  • 插件开发者无权访问我的代码。否则,是的,我可以定义接口。
  • @CharlieSalts 那么插件开发者是如何编写插件的呢?当然,他们必须实现IPlugIn 或其他东西。还是完全是动态的?
  • 我假设如果我们使用相同的接口,它会起作用(就像使用 C 头文件一样)。所有方法名称都相同,类名相同,依此类推。正如其他人指出的那样,这并不能使他们平等。
【解决方案3】:

.NET 中可扩展应用程序的典型骨架由以下程序集组成:

  • 合同组装。这个包含插件的合约(只是接口,以及可选的一些数据合约,用于接口)和主机合约;
  • 主机程序集。这一个包含主机合同实现,并依赖于第一个;
  • 几个插件程序集。这些程序集包含插件契约实现,并且也依赖于第一个。

因此,使用合同组装,您可以实现主机和插件彼此独立(因此,插件 是后期绑定的),但它们有共同的合同,在编译时已知 -双方(插件和主机)的时间。

你的方式(多次定义插件联系人)是错误的方式。

【讨论】:

    【解决方案4】:

    正如其他人所提到的,这些是单独的接口,处理此问题的正确方法是将定义放入两者都引用的第三个程序集中。

    但是...有一种方法可以通过使用名为Impromptu Interface 的库来实现这一点。

    【讨论】:

      猜你喜欢
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-22
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多