如何创建具有热插拔功能的松散耦合架构?

时间:2010-11-01 09:59:44

标签: c# .net visual-studio architecture

我有兴趣创建一个由模块组成的桌面应用程序,这些模块的源代码嵌入在应用程序本身中,允许用户在运行它时编辑应用程序。在不重新启动应用程序的情况下使用更新的模块。任何人都可以为此建议一个好的架构吗?

我希望使用Microsoft.Net和C#。 DLR不是一种选择。

谢谢!

3 个答案:

答案 0 :(得分:2)

在短篇文章中建议一个好的架构并不容易。

首先,我定义了用户编写/修改的每个模块必须实现的契约(接口)。它应该至少包含一个Execute方法。

然后我会为这些模块创建一个Wrapper-Class:

  1. 从文件加载源代码
  2. 包装器编译文件并确保它实现合同
  3. 包含文件是否可以成功编译的指示
  4. 它还应该实现合同,以便于调用和处理
  5. 然后我会有一些包含所有模块包装器集合的shell。然后,任何成功编译的包装器都会让Shell调用模块接口的Execute方法。

    在动态编译和执行代码时,此链接应提供您需要的所有信息: http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

答案 1 :(得分:0)

嗯,动态语言肯定是最合适的......

您可以使用System.Reflection.Emit命名空间中的类型动态创建程序集。

然而,会非常痛苦,因为您需要将这些动态程序集加载到自定义AppDomains中,否则您将无法再次卸载它们。

这再次意味着您必须解决与跨AppDomain通信相关的编组和程序集解决问题。

答案 2 :(得分:-1)

您可能正在寻找的是依赖注入的概念。

依赖注入意味着模块X不是直接使用模块Y,而是依赖于接口,而应用程序告诉模块X哪个实现应该使用它,例如:使用模块Y。

有几种实现依赖注入的方法。一种是引用每个模块中的接口,并明确让应用程序使用正确的接口实现配置每个模块。

实现它的第二个问题(可能在你的情况下最有用)是使用中央注册表。定义您希望在应用程序中拥有的所有接口。这些是您要动态更改实现的接口。然后定义这些接口的标识。这些可以是字符串或整数或GUID。 然后在应用程序中创建一个映射,将映射映射到接口,并使用正确的接口实现填充映射。在C ++应用程序中(我还不熟悉C#),这可能是这样的:

std::map<std::string,IInterface> appInterfaces;
appInterfaces["database"] = new OracleDatabaseModule();
appInterfaces["userinterface"] = new VistaStyleUserInterface();

当他们想要使用其中一个模块时,让所有模块都进入这个中央注册表。确保它们不直接访问模块,但它们只通过注册表传递。 E.g。

MyModule::someMethod()
{
IDatabaseInterface *dbInterface = dynamic_cast<IDatabaseInterface *>(appInterfaces["database"]);
dbInterface->executeQuery(...);
}

如果您现在想要更改应用程序中接口的实现,您只需更改注册表中的条目,如下所示:

IInterface *iface = appInterfaces["database"];
if (iface) delete iface;
appInterface["database"] = new SqlServerDatabaseInterface();