7

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

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

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

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

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

4

3 回答 3

12

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

但是,您可以将插件放在单独的导出提供程序中并给予优先权。在这里,我为应用程序文件夹中的“插件”子文件夹执行此操作:

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;

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

于 2012-06-26T08:27:52.467 回答
3

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

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

于 2012-06-25T20:10:36.053 回答
1

我不确定会有多大意义,但让我试试。

我会TaxCalculatorManager上课。该类可以ITaxCalculator从 MEF 加载所有实现。从那里,您可以在Export属性中包含一些允许对实现进行排名的东西。然后,当您需要计算税收时,您会调用TaxCalculatorManager.Calculatewhich 将对ITaxCalculator实现进行排名并调用Calculate获胜者。

如果您需要我澄清任何问题,请告诉我。

于 2012-06-25T20:18:06.687 回答