我将我的问题分为短版和长版,供手头时间不多的人使用。
简洁版本:
我需要一些具有提供者和消费者插件的系统架构。提供者应该实现接口 IProvider,消费者应该实现 IConsumer。执行应用程序应该只知道 IProvider 和 IConsumer。消费者实现可以询问正在执行的程序集(通过 ServiceProcessor)哪些提供者实现了 InterfaceX 并获取一个 List。这些 IProvider 对象应该被强制转换为 InterfaceX(在消费者中),以便能够将消费者挂钩到 InterfaceX 定义的某些事件上。这将失败,因为执行程序集不知何故不知道此 InterfaceX 类型(转换失败)。解决方案是将 InterfaceX 包含到插件和执行程序集都引用的某个程序集中,但这应该意味着对每个新的提供者/消费者对都进行重新编译,这是非常不受欢迎的。
有什么建议么?
长版:
我正在开发某种通用服务,它将使用插件来实现更高级别的可重用性。该服务由某种使用提供者和消费者的观察者模式实现组成。提供者和消费者都应该是主应用程序的插件。让我首先通过列出我的解决方案中的项目来解释服务是如何工作的。
项目 A:用于托管所有插件和基本功能的 Windows 服务项目。TestGUI Windows 窗体项目用于更轻松的调试。来自项目 B 的 ServiceProcessor 类的一个实例正在执行与插件相关的工作。该项目的子文件夹“Consumers”和“Providers”包含子文件夹,其中每个子文件夹分别包含一个消费者或提供者插件。
项目 B:一个类库,包含 ServiceProcessor 类(执行插件之间的所有插件加载和调度等)、IConsumer 和 IProvider。
项目C:一个类库,链接到项目B,由TestConsumer(实现IConsumer)和TestProvider(实现IProvider)组成。TestProvider 实现了一个附加接口(ITest,它本身是从 IProvider 派生的)。
这里的目标是消费者插件可以询问服务处理器它有哪些提供者(至少实现 IProvider)。返回的 IProvider 对象应在 IConsumer 实现中强制转换为它实现的其他接口 (ITest),以便使用者可以将事件处理程序挂钩到 ITest 事件。
项目 A 启动时,会加载包含使用者和提供者插件的子文件夹。以下是我迄今为止遇到并试图解决的一些问题。
ITest 曾经驻留在项目 C 中的接口,因为这只适用于 TestProvider 和 TestConsumer 知道的方法和事件。总的想法是保持项目 A 简单,不知道插件之间的作用。
使用项目 C 中的 ITest 以及将 IProvider 转换为 ITest 的 TestConsumer 的 Initialize 方法中的代码(当实现 ITest 的对象被称为 IConsumer 对象时,这在单个类库本身中不会失败)会发生无效的转换错误. 可以通过将 ITest 接口放入项目 A 引用的项目 B 中来解决此错误。这是非常不需要的,因为我们需要在构建新接口时重新编译项目 A。
我试图将 ITest 放在仅由项目 C 引用的单个类库中,因为只有提供者和消费者需要了解此接口,但没有成功:加载插件时,CLR 指出找不到引用的项目。这可以通过挂钩当前 AppDomain 的 AssemblyResolve 事件来解决,但不知何故这似乎也不需要。ITest 再次回到项目 B。
我试图将项目 C 拆分为消费者和提供者的单独项目,并且都加载本身运行良好的程序集:两个程序集都驻留在 Assemblies 集合或当前 AppDomain 中:发现程序集:Datamex.Projects.Polaris.Testing.Providers ,版本=1.0.0.0,文化=中性,PublicKeyToken=2813de212e2efcd3 发现程序集:Datamex.Projects.Polaris.Testing.Consumers,版本=1.0.0.0,文化=中性,PublicKeyToken=ea5901de8cdcb258
由于消费者使用提供者,因此消费者对提供者进行了引用。现在再次触发 AssemblyResolve 事件,说明它需要以下文件:AssemblyName=Datamex.Projects.Polaris.Testing.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2813de212e2efcd3
我的问题:为什么会这样?这个文件已经加载对了吗?为什么从 IProvider 转换到我知道它实现的某个接口是不可能的?这可能是因为执行程序本身不知道这个接口,但是这个不能动态加载吗?
我的最终目标:消费者插件询问 ServiceProcessor 它有哪些提供者实现了接口 x。提供者可以被强制转换为这个接口 x,而无需执行程序集知道接口 x。
有人可以帮忙吗?
在此先感谢,埃里克