C# mef枚举导出和体系结构

C# mef枚举导出和体系结构,c#,architecture,mef,C#,Architecture,Mef,我想让我的插件子系统使用mef,但我没有什么问题,因为我是csharp和mef的新手( 我想做的是: 每个插件都可以创建自己的接口IPlugin1、IPlugin2 这些接口中的每一个都必须具有指定的加载、卸载功能 使用mef我想枚举所有导出并调用Load/Unload 问题是: a、 我的解决方案好吗?如果没有,我如何改进它(通过使用其他方法) b、 如何使用mef枚举所有导出并调用指定的接口函数 非常感谢所有链接和评论。谢谢大家。如果您希望所有插件接口都遵循自己的接口,那么您应该为他们提供一

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

我想做的是:

  • 每个插件都可以创建自己的接口IPlugin1、IPlugin2
  • 这些接口中的每一个都必须具有指定的加载、卸载功能
  • 使用mef我想枚举所有导出并调用Load/Unload
  • 问题是:

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

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


    非常感谢所有链接和评论。谢谢大家。

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

    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<IMyInterface> Plugins { get; set; }
    }
    
    公共类SomeClass
    {
    [进口数量(类型(IMyInterface))]
    私有IEnumerable插件{get;set;}
    }
    
    如果一切都连接正确,
    Plugins
    将是类的枚举,通过继承,这些类将导出为
    IMyInterface
    s


    资源:


    关于@ My y的回答,我认为有一个通用的接口是你可以使用的最好的设计。这是最简单的方法来利用你可以应用到插件上的一组通用操作。
    public interface IPlugin : IDisposable
    {
        void Initialise();
    }
    
    通过实施
    Dispose
    方法,您可以通过
    CompositionContainer
    的生存期管理功能自动控制零件。您所有的卸载代码都可以放在那里,下面是一个示例插件:

    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
    实例将跟踪此项,并在清理时将其清理

    现在,我想描述的是在InterceptingCatalog中添加的一个很好的功能。这个目录允许您注册拦截策略,它可以让您在导出值返回到调用代码之前访问导出值。其中一个用途是自动确保在bas上调用
    Initialise
    第一次导出实例时的e
    IPlugin
    接口:

    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<ILogger>();
    
        logger.Log("test");
    
        Console.ReadKey();
    }
    
    static void Main(字符串[]args)
    {
    var catalog=新的AssemblyCatalog(typeof(Program).Assembly);
    var配置=新的侦听配置()
    .AddInterceptor(新的初始值为pluginstrategy());
    var interceptingCatalog=新的interceptingCatalog(目录,配置);
    var container=新合成容器(拦截目录);
    var logger=container.GetExportedValue();
    logger.Log(“测试”);
    Console.ReadKey();
    }
    
    如果您运行它,您会注意到我们的
    ConsoleLogger
    会在我们第一次从容器中获取它时自动初始化。我们不必担心它会再次初始化,它只会在创建导出实例时进行初始化,这意味着它遵守单例和非单例场景

    此时,您可能会认为这可能有些过分,但实际上这是一个非常优雅的解决方案,可以让您的部件自动启动,并在不再需要时进行处理

    当然,如果你想细细控制你的部分是如何被初始化的,你可以在你自己编写的方法中管理这些,你只需要考虑插件状态就可以了。


    您可以在

    中阅读关于拦截目录的更多信息,您也应该考虑导出<代码> IMyPosie >与<代码> IpLuxIn的导出不相同。我建议,导出为您想要的<代码> iPuxLin 1/代码>,然后执行一个强制转换到<代码> IyMyFutue<代码>,操作<代码>加载<代码> >代码>。卸载。您需要这样做,因为MEF将尝试根据其导出定义实例化类型,这意味着如果您导入
    IMyInterface
    IPlugin1
    ,它将实例化至少两个插件的独立实例(无论
    CreationPolicy
    )@Matthew:这绝对是一种可能性。我给出这个例子的原因是OP说他想要一个枚举。在“插件”之间没有公共接口他正在寻找我提出的建议之外的内容,即让它们各自继承自
    IMyInterface
    。另一种方法是将IPlugin1、IPlugin2等作为单个成员导入,然后使用
    ipartimportssatifiedNotification
    接口将它们全部添加到作为
    IMyInterface
    转换的集合中我认为重要的IMyInterface是更好的途径。不过,你应该提出你的替代解决方案。非常感谢。我能说什么?我希望有像你这样的经验。再次感谢你,我不使用asp.net mvc。在桌面应用程序中一切都很好,但在asp.net mvc中,我出现错误“无法转换类型的基本导出值”调用container.GetExportedValue();。是否有mvc应用程序的解决方案或修复此错误?谢谢