如何使用MEF允许插件覆盖现有功能?

Chr*_*nte 7 c# mef

我正在使用MEF来允许用户扩展我的C#库.它到目前为止工作得很好,但是现在我正试图以我以前没见过的方式使用它.

我到目前为止看到的MEF的主要用例是:

  • 应用程序公开原始接口(IPerson)
  • 外部库使用MEF和原始接口来扩展主库的功能(例如IPoliceman : IPerson,添加功能)
  • 然后ImportMany,应用程序IPerson根据必须执行的操作用于搜索正确的内容

但我需要这样的事情:假设我有一个税收计算器,它接受一堆参数并根据这些参数返回估计税.我希望用户能够使用MEF创建插件来修改这些计算的完成方式.应该只能在任何时候加载一个执行此操作的插件.否则,我如何决定使用哪种替代实现?

所以基本上,我的问题归结为:通常MEF允许添加类和方法的实现.如何使用它来允许用户替换实现?

Wim*_*nen 12

通常,当您尝试覆盖应用程序中已存在的导出时,您将获得一个基数异常,[Import(typeof(IFoo)]因为MEF预计只有一个匹配的导出可用.

但是,您可以将插件放在单独的导出提供程序中并赋予其优先级.在这里,我为应用程序文件夹中的"plugins"子文件夹执行此操作:

Assembly executingAssembly = Assembly.GetExecutingAssembly();
string exeLocation = Path.GetDirectoryName(executingAssembly.Location);
string pluginPath = Path.Combine(exeLocation, "plugins");

var pluginCatalog = new DirectoryCatalog(pluginPath);
var pluginExportProvider = new CatalogExportProvider(pluginCatalog);

var appCatalog = new DirectoryCatalog(exeLocation,"*");
var appExportProvider = new CatalogExportProvider(appCatalog);

var container = new CompositionContainer(
    pluginExportProvider, appExportProvider);

pluginExportProvider.SourceProvider = container;
appExportProvider.SourceProvider = container;
Run Code Online (Sandbox Code Playgroud)

传递给组合容器的导出提供程序的顺序决定了优先级:如果插件和应用程序部分都提供了导出,那么插件将获得优先级.


Tim*_*ver 3

你所说的实际上只是看待同一问题的不同方式。答案比听起来更简单 - 对于您希望客户端能够覆盖的任何行为,只需将该行为放入插件中即可。

没有什么说你不能仅仅因为你是应用程序的作者就不能编写插件。将您的 TaxCalculator 类放入插件中,并公开一个接口,允许用户编写自己的税务计算器。在运行时,如果您加载了多个加载项,请选择不属于您的加载项。开箱即用,您将使用税务计算器插件,因此它将完全按照您期望的方式工作。如果用户创建自己的税务计算器插件并将其放入正确的目录中,则您可以使用它,从而有效地允许他们“覆盖”您的原始功能。