首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mef出口和建筑

mef出口和建筑
EN

Stack Overflow用户
提问于 2011-09-12 12:47:54
回答 2查看 1.2K关注 0票数 0

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

我想做的是:

  1. 每个插件都可以创建自己的接口IPlugin1,IPlugin2 .
  2. 这些接口中的每一个都必须有指定的函数--加载、卸载
  3. 使用mef,我希望激活所有导出并调用加载/卸载

问题如下:

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

如何使用mef激活所有导出并调用指定的接口函数?

我将感谢所有的联系和批评。谢谢大家。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-09-12 17:47:30

基于@m的回答,我确实认为拥有一个公共界面是最好的设计。这是利用通用操作集的最简单方法,您可以将这些操作应用到插件中。不过,我要考虑的是,略为完善一下:

代码语言:javascript
复制
public interface IPlugin : IDisposable
{
    void Initialise();
}

通过强制实现Dispose方法,您的部件可以由CompositionContainer的生存期管理特性自动控制。所有的卸载代码都可以放进去,下面是一个示例插件:

代码语言:javascript
复制
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。此目录允许您执行的是注册拦截策略,它允许您在将导出的值返回给调用代码之前访问它。其中一个用途可以是在第一次导出实例时自动确保在基本Initialise接口上调用IPlugin

代码语言:javascript
复制
public class InitialisePluginStrategy : IExportedValueInterceptor
{
    public object Intercept(object value)
    {
        var plugin = value as IPlugin;
        if (plugin != null)
            plugin.Initialise();

        return value;
    }
}

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

代码语言:javascript
复制
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<ILogger>();

    logger.Log("test");

    Console.ReadKey();
}

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

在这一点上,您可能会认为这可能会造成太大的损失,但实际上,这是一个非常优雅的解决方案,可以使您的部件自动启动,并在不再需要时进行处理。

当然,如果您想要对如何初始化您的部件进行细粒度的控制,您只需在您自己编写的方法中管理这些组件,那么您只需要考虑插件状态。

你可以在Piotr Włodek博客上读到更多关于Piotr Włodek博客的文章。

票数 1
EN

Stack Overflow用户

发布于 2011-09-12 13:21:40

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

代码语言:javascript
复制
public interface IMyInterface
{
    void Load();
    void Unload();
}

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

代码语言:javascript
复制
public interface IPlugin1 : IMyInterface
{
    void DoPlugin1Func();
}

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

代码语言:javascript
复制
[InheritedExport(typeof(IMyInterface))]
public interface IMyInterface { ... }

这说明任何从IMyInterface扩展的类都将作为一种IMyInterface类型导出,甚至在树下也是如此:

代码语言:javascript
复制
//This class will be exported as an IMyInterface
public class PluginImplementation1 : IPlugin1 { ... }

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

代码语言:javascript
复制
public class SomeClass
{
    [ImportMany(typeof(IMyInterface))]
    private IEnumerable<IMyInterface> Plugins { get; set; }
}

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

资源:

  • InheritedExport实例
  • ImportMany实例
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7388115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档