mef enum出口和建筑

我想用mef制作我的插件子系统,但我有几个问题,因为我是csharp和mef的新手(

我想做的事:

  1. 每个插件都可以创建自己的接口IPlugin1,IPlugin2 ……
  2. 每个接口都必须具有指定的functionLoad,Unload
  3. 使用mef我想枚举所有导出并调用加载/卸载

问题:

一个。 我的解决方案是否良好,如果没有,我如何改进它(通过使用其他东西)?

湾 如何使用mef枚举所有导出并调用指定的接口函数?

我会感谢所有链接和评论家。 谢谢大家。

基于@ my的答案,我认为拥有一个通用界面是您可以使用的最佳设计。 这是利用可应用于插件的一组通用操作的最简单方法。 我会考虑的是稍微改进一下:

public interface IPlugin : IDisposable { void Initialise(); } 

通过强制执行Dispose方法,您可以自动控制CompositionContainer的生命周期管理function。 所有卸载代码都可以进入,这里有一个示例插件:

 public interface ILogger : IPlugin { void Log(string message); } [Export(typeof(ILogger))] public class ConsoleLogger : ILogger { void IPlugin.Initialise() { Console.WriteLine("Initialising plugin..."); } public void Log(string message) { Console.WriteLine(message); } public virtual void Dispose(bool disposing) { if (disposing) { Console.WriteLine("Disposing plugin..."); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

Dispose模式允许使用标准化机制来清理代码。 您的CompositionContainer实例将跟踪此项目,并在处理时清理它。

现在,我想要描述的是MEFContrib中一个名为InterceptingCatalog的新增function 。 这个目录允许你做的是注册拦截策略,它可以让你在返回到你的调用代码之前访问一个导出的值。 一个这样的用法可能是自动确保在第一次导出实例时在基本IPlugin接口上IPlugin Initialise

 public class InitialisePluginStrategy : IExportedValueInterceptor { public object Intercept(object value) { var plugin = value as IPlugin; if (plugin != null) plugin.Initialise(); return value; } } 

让我们把这一切联系起来:

 static void Main(string[] args) { var catalog = new AssemblyCatalog(typeof(Program).Assembly); var configuration = new InterceptionConfiguration() .AddInterceptor(new InitialisePluginStrategy()); var interceptingCatalog = new InterceptingCatalog(catalog, configuration); var container = new CompositionContainer(interceptingCatalog); var logger = container.GetExportedValue(); logger.Log("test"); Console.ReadKey(); } 

如果你运行它,你会注意到我们的ConsoleLogger会在我们第一次从容器中获取时自动初始化。 我们不需要担心它会再次初始化,它只会在创建导出的实例时这样做,这意味着它服从单例和非单例场景。

你可能会想到这可能是矫枉过正,但它实际上是一个非常优雅的解决方案,可以让你的零件自动启动,并在不再需要时处理掉。

当然,如果你想对你的部件初始化方式进行细致的控制,你可以用你自己编写的方法来管理它们,你只需要考虑插件状态。

您可以在PiotrWłodek的博客上阅读更多有关InterceptingCatalog的信息

如果您希望所有插件接口都遵循自己的接口,那么您应该为它们提供扩展接口:

 public interface IMyInterface { void Load(); void Unload(); } 

然后,当插件创建自己的接口时,它们应该从您公开提供的接口扩展:

 public interface IPlugin1 : IMyInterface { void DoPlugin1Func(); } 

现在,为了获得在MEF中导出的接口集合,您必须将接口标记为InheritedExport:

 [InheritedExport(typeof(IMyInterface))] public interface IMyInterface { ... } 

这表明任何以某种方式从IMyInterface扩展的类都将作为一种IMyInterface导出,甚至在树下:

 //This class will be exported as an IMyInterface public class PluginImplementation1 : IPlugin1 { ... } 

最后,在代码中的某处(如果适用),您可以导入IMyInterface实例的集合。

 public class SomeClass { [ImportMany(typeof(IMyInterface))] private IEnumerable Plugins { get; set; } } 

如果一切都正确连接, Plugins将是一个类的枚举,通过inheritance,导出为IMyInterface


资源:

  • InheritedExport示例
  • ImportMany示例