允许C#插件在应用程序挂钩上注册

lys*_*cid 8 .net c# architecture plugins

我正在构建一个基于.NET的应用程序,并希望允许更可扩展和可插入的设计.

为简单起见,应用程序公开了一组操作和事件:

  • 做一点事()
  • DoOtherThing()
  • 的OnError
  • 的onSuccess

我想提供"插件"来加载并挂钩其中一些操作(类似于:当Event1触发时,运行plugin1).

例如 - 当OnError事件触发时运行plugin1.HandleError().

这可以通过事件订阅轻松完成:

this.OnError += new Plugin1().HandleError();
Run Code Online (Sandbox Code Playgroud)

问题是:

  1. 我的应用程序不知道类型"Plugin1"(它是一个插件,我的应用程序不直接引用它).
  2. 这样做会在时间之前实例化插件,这是我不想做的事情.

在"传统"插件模型中,应用程序(插件的"客户端")在某些关键点加载并执行插件代码.例如 - 执行特定操作时的图像处理应用程序.

客户端应用程序知道何时实例化插件代码以及何时执行它.

在我的应用程序中,插件本身将决定它应该何时执行("插件应该在OnError事件上注册").

保持插件"执行"代码与"注册"代码一起构成了一个问题,即插件DLL将在注册时加载到内存中,这是我希望防止的.

例如,如果我在插件DLL中添加Register()方法,则必须将插件DLL加载到内存中以便调用Register方法.

对于这个特定问题,什么是一个好的设计解决方案?

  • 懒惰地加载(或提供延迟/急切加载)插件DLL.
  • 允许插件控制他们挂钩的系统/应用程序的各个部分.

Han*_*ant 5

您正在尝试解决不存在的问题.代码调用Assembly.LoadFrom()时加载的所有类型的心理图像都是错误的..NET框架充分利用Windows作为需求分页的虚拟内存操作系统.然后还有一些.

调用LoadFrom()时,球会滚动.使CLR创建一个内存映射文件,一个核心操作系统抽象.它会更新一些内部状态以跟踪现在驻留在AppDomain中的程序集,它非常小.MMF设置内存映射,创建映射文件内容的虚拟内存页.只是处理器TLB中的一个小描述符.实际上没有从程序集文件中读取任何内容.

接下来,您将使用反射来尝试发现实现接口的类型.这导致CLR从程序集中读取一些程序集元数据.此时,页面错误导致处理器将覆盖程序集元数据部分的某些页面的内容映射到RAM.少量千字节,如果组件包含很多类型,可能更多.

接下来,即时编译器开始执行以生成构造函数的代码.这会导致处理器将包含构造函数IL的页面置入RAM.

等等.核心思想是,只有在需要才能懒散地阅读汇编内容.这种机制对于插件没有什么不同,它们的工作方式与解决方案中的常规程序集一样.唯一的区别是订单略有不同.首先加载程序集,然后立即调用构造函数.与在代码和CLR中调用类型的构造函数相反,然后立即加载程序集.这需要同样长的时间.


Osk*_*lin 4

您需要做的是找到dll的路径,然后从中创建一个程序集对象。从那里,您将需要获取您希望检索的类(例如,实现您的接口的任何内容):

var assembly = Assembly.Load(AssemblyName.GetAssemblyName(fileFullName));
foreach (Type t in assembly.GetTypes())
{
  if (!typeof(IMyPluginInterface).IsAssignableFrom(t)) continue;
  var instance = Activator.CreateInstance(t) as IMyPluginInterface;
  //Voila, you have lazy loaded the plugin dll and hooked the plugin class to your code
}
Run Code Online (Sandbox Code Playgroud)

当然,从这里你可以自由地做任何你想做的事,使用方法,订阅事件等。