zoukankan      html  css  js  c++  java
  • MEF和CompositionContainer学习

    最近在研究项目平台启动,发现使用的是CompositionContainer,就对其起了兴趣,初步研究了一下,发现时MS提供的扩展性框架 MEF,下面是本人的一点心得和大家共同探讨。

    MEF定义:

    Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)等。MEF为开发人员提供了一个工具,让我们可以轻松的对应用
    程序进行扩展并且对已有的代码产生最小的影响,开发人员在开发过程中根据功能要求定义一些扩展点,之后扩展人员就可以使用这些扩展点与应用程序交互;同时MEF让应用程序与扩展程序
    之间不产生直接的依赖,这样也允许在多个具有同样的扩展需求之间共享扩展程序。

    MEF组件,以Part形式,同事有Import和Export功能。

    MEF导入导出:导入导出的类都继承同一个接口,然后把类实例化,最后在总的容器里导入。

    接下来用代码实战了:

    1:首先定义一个Metadata,可以附加自身附件信息。
    元数据可用于将导出的对象的属性传递到导入部件。 导入部件可以使用此数据来决定要使用哪些导出,或收集有关导出的信息而不必构造导出。元数据视图接口必须只有属性,并且这些属性
    必须具有 get 访问器。

    public interface IPartInformation
        {
            string Name { get; }
    
            string Version { get; }
    
            Type PartType { get; }
    
            [DefaultValue(null)]
            Type[] Dependencies { get; }
    
            string Author { get; }
    
            string Contact { get; }
    
            string Date { get; }
    
            string Description { get; }
    
            string Comment { get; }
        }

    2:定义一个公共接口,供导入导出继承

    public interface ISinglePart
        {
        }

    3:增加一个Class Library继承ISinglePart,同时标注Metadata和Export标签

        [Export(typeof(ISinglePart))]
        [ExportMetadata("Name","123")]
        [ExportMetadata("PartType", typeof(Class1))]
        [ExportMetadata("Author", "123")]
        [ExportMetadata("Contact", "123")]
        [ExportMetadata("Version", "2.0.0.0")]
        [ExportMetadata("Date", "2013/03/28")]
        [ExportMetadata("Description", "1234")]
        [ExportMetadata("Comment", "12345")]
        public class Class1:ISinglePart
        {
        }

    4:增加MEF发现部件的方式:使用AssemblyCatalog 在当前程序集发现部件。

    public class RecursiveDirectoryCatalog:ComposablePartCatalog
        {
            private AggregateCatalog _innerCatalog = null;
    
            public RecursiveDirectoryCatalog(string basePath, params string[] dirPaths)
            {
                var fullDirPaths = from p in dirPaths
                                   let d = Path.IsPathRooted(p) ? p : Path.Combine(basePath, p)
                                   select d;
    
                var asmCatalogs = from p in fullDirPaths
                                  from dll in Directory.GetFiles(p, "*.dll", SearchOption.AllDirectories)
                                  let cb = new AssemblyName().CodeBase = dll
                                  where AssemblyHelp.IsManageDll(dll)
                                  select new AssemblyCatalog(cb);
    
                _innerCatalog = new AggregateCatalog(asmCatalogs.OfType<ComposablePartCatalog>());
            }
    
            public override IQueryable<ComposablePartDefinition> Parts
            {
                get { return _innerCatalog.Parts; }
            }
    
            
        }

    5:组合部件
    在加载完部件之后,要把它们放到一个CompositionContainer容器中。

    var catalog = new RecursiveDirectoryCatalog(basePath, partDirectories);
    this.Container = new CompositionContainer(catalog);

    6:导入程序负责指定将使用的元数据视图(如果有)。 包含元数据的导入将声明为延迟导入,其元数据接口作为 Lazy<T,T> 的第二个类型参数。 下面的类导入前面的部件以及元数据。

    创建策略
    当部件指定执行导入和组合时,组合容器将尝试查找匹配的导出。 如果它将导入与导出成功匹配,则导入成员将设置为导出的对象的实例。 导出部件的创建策略控制此实例来源于何处。导
    入和导出都可从值 Shared、NonShared 或 Any 中指定部件的创建策略。 导入和导出的默认值均为 Any。

    [ImportMany(RequiredCreationPolicy = CreationPolicy.Shared)]
    public IEnumerable<Lazy<TSingle, IPartInformation>> SingleParts { get; private set; }

    7:将指定部分加入CompositionBatch物件中,在容器上执行组合,包括指定的 CompositionBatch 中的更改,这样就能把Class1以及其Metadata导入至SingleParts中

    var batch = new CompositionBatch();
    batch.AddExportedValue(owner);
    batch.AddExportedValue(this.Container);
    batch.AddPart(this);

    8:关于生命周期和释放

    由于部件承载于组合容器中,因此其生命周期可能比普通对象更复杂,所以将只有拥有部件的容器才应对其调用 Dispose 方法。 容器本身实现 IDisposable,并且作为 Dispose 中其清理的
    一部分,它将对拥有的所有部件调用 Dispose。

     public partial class AstPartContainer<TOwner, TSingle, TMultiple> : IDisposable
            where TOwner : class
            where TSingle : class
            where TMultiple : class
        {
        }

    最后总结一下使用MEF,到底有什么用处?
    假设项目中包含有大量的小组件,并且每一个组件都是都不同的开发小组开发的,甚至都无法提供源码,这样您就无法在不修改大量源码的情况下添加新的组件,但是如果使用MEF,对于同一
    类型的组件继承同一个接口,定义导入导出,这样只需要提供相关DLL,就能以Part的形式加入容器中,供开发人员调用。其具有很强灵活性的可扩展支持

  • 相关阅读:
    jvm垃圾回收机制
    java中transient关键字的含义
    com.alipay.sofa.rpc.core.exception.SofaRouteException: RPC-02306: 没有获得服务[io.sofastack.balance.manage.facade.BalanceMngFacade:1.0:user77]的调用地址,请检查服务是否已经推送
    IDEA失效的解决办法
    多线程
    Java对象的创建过程
    注解(Annotation)
    面向对象思想
    IDEA--java版本修改(jdk1.8改成jdk1.7)
    HttpClient
  • 原文地址:https://www.cnblogs.com/gavinhuang/p/2988459.html
Copyright © 2011-2022 走看看