zoukankan      html  css  js  c++  java
  • MEF学习总结(3)---Attribute Model Programing

    上一片介绍了Primitive层,Attribute Model可以认为是对Primitive的上层实现。主要包括如下内容:

    1. 一系列的Attribute来定义Import和Export

    常用的有如下Attribute:Export,InheritedExport,Import,ImportConstructor,ImportMany,ExportMetadata

    Export:如果需要将某个class定义为可供其他组件Import的组件,只需将Export attribute应用于该class即可。这相当于申明了一个ExportDefinition.

    例如:

    [Export]
    class Person
    {
          public string Name { get; set; }
    
           public string Age { get; set; }
    }

    这里将Person类导出,依赖Person的组件可以通过Import Attribute来定义依赖。

    ExportAttribute有两个属性,ContractName和Type,其实都是用来标识Export的,用来在Import的时候指定依赖目标。在没有显示设置情况下,默认是用Type来标识。

    InheritedExport是将Export定义在基类上,所有派生类自动应用基类的Export

    Import: 其他组件如果需要依赖声明为Export的组件,则使用Import Attribute来指定。

    例如:

    class Company
    {
      [Import]
      private Person _chairMan
    }

    这里Company类定义了自身对Person组件的依赖。ImportAttribute也有ContractName和Type属性,用来定义所依赖组件的标识符。

    ImportConstructor:通过该Attributes来定义容器创建组件是使用的构造函数,函数的参数自动定义为Import,会通过容器来注入。

    ImportMany:导入所有满足条件的组件实例。参考如下代码:

    public interface ILog
        {
    
        }
    
        [Export(typeof(ILog))]
        public class FileLog : ILog
        {
    
        }
    
        [Export(typeof(ILog))]
        public class DBLog : ILog
        {
    
        }
    
    
        public class TaskExecutor
        {
            [ImportMany(typeof(ILog))]//声明注入所有提供ILog接口的组件实例
            public IEnumerable<ILog> _loggers;
        }
    
    class Program
        {
    
            static void Main(string[] args)
            {
    
                var container = new CompositionContainer(new ApplicationCatalog());
    
                var executor = new TaskExecutor();
                container.ComposeParts(executor);// FileLog 和 DBLog都会注入_logger数组
    
                Console.ReadKey();
            }
        }

    ExportMetadata:有时候ImportMany的时候我们不希望对满足导出接口的所有组件实例进行进一步筛选.这个时候可以通过ExportMetadata来定义Export的组件具有哪些特性,然后在依赖组件中对导入的组件根据Metadata进行筛选。依然用上面的例子,可以这样来进行筛选。

    [Export(typeof(ILog))]
        [ExportMetadata("Type", "db")]
        public class DBLog : ILog
        {
    
        }
    
      //需要定义一个接口来声明Export所支持的metadata
    public interface ILogMetadata { string Type { get; } } public class TaskExecutor { [ImportMany(typeof(ILog))] public IEnumerable<Lazy<ILog, ILogMetadata>> _loggers;//这里将变量类型声明为Lazy<ILog,ILogMetadata>,这样在依赖注入的时候不会创建组件的实例 public IEnumerable<ILog> AvailableLogger { get { var result = new List<ILog>(); foreach (var logger in _loggers) {
                //对metadata进行筛选
    if (logger.Metadata.Type == "db") { result.Add(logger.Value); } } return result; } } }

    CreationPolicy:

    在将组件通过ExportAttribute导出的时候,可以通过PartCreationPolicyAttributes来指定该组件的实例创建法则.有如下几种选项:

    Any //将选择权交给Container来决策,该选项是默认选项,而Container层一般是选择Shared

    NonShared //每次填充依赖的时候都创建一个新的组件实例来满足Import

    Shared //以单例的形式创建组件实例

    同时在定义Import的时候也能指定所需求的组件实例的形式。可以通过设置Import的RequiredCreationPolicy属性来指定。这样就会出现Import的CreationPolicy和Export的CreationPolicy不一致的问题。两者组合最终得到的结果如下:

                                     || Part.Any     ||     Part.Shared     ||     Part.NonShared || 
    | Import.Any              | Shared        |        Shared           |     Non Shared         | 
    | Import.Shared         | Shared        |        Shared           |     No Match            | 
    | Import.NonShared  | Non Shared |        No Match      |     Non Shared         |

    2. 一系列发现和生成ComposablePartDefinition的ComposablePartCatalog

    PartCatalog是按一定规则来发现Composable Part,并生成对应的ComposablePartDefinition。MEF提供了如下几种Catalog:

    System.ComponentModel.Composition.Primitives.ComposablePartCatalog
        System.ComponentModel.Composition.Hosting.AggregateCatalog //可以组合几种Catalog
        System.ComponentModel.Composition.Hosting.ApplicationCatalog //在应用程序目录中的Dll和Exe中发现组件
        System.ComponentModel.Composition.Hosting.AssemblyCatalog //在指定的Assembly中发现组件
        System.ComponentModel.Composition.Hosting.CompositionScopeDefinition //这个还没用过
        System.ComponentModel.Composition.Hosting.DirectoryCatalog //在指定目录中的dll和exe中发现组件
        System.ComponentModel.Composition.Hosting.FilteredCatalog //基于指定的Catalog来应用一个Filter,产生新的Catalog
        System.ComponentModel.Composition.Hosting.TypeCatalog //基于一组类型来发现组件

    当将Catalog注册到Container中之后,Catalog会自动去发现Composable Part,并车安生对应的Definition.

    3. AttributedModelService

    除了定义上述的规则,然后让Container去自动发现组件,生成PartDefinition,和创建Part外。AttributedModelService类提供了若干方法可以手动的去创建PartDefinition,创建Part,添加Part,注入依赖。

    [Export]
        public class Person
        {
            public string Name { get; set; }
    
            public string Age { get; set; }
        }
    
        [Export]
        public class Company
        {
            [Import]
            public Person ChairMan { get; set; }
        }
    
        class Program
        {
            
            static void Main(string[] args)
            {
                var container = new CompositionContainer(new ApplicationCatalog());
                
                var company = new Company();
                var person = new Person();
                
                var personPart = AttributedModelServices.CreatePart(person);
                var companyPart = AttributedModelServices.CreatePart(company);
    
                var batch = new CompositionBatch();
                batch.AddPart(personPart);
                batch.AddPart(companyPart);
    
                container.Compose(batch);
    
                Console.ReadKey();
            }

    上述代码就是通过手动创建Part,然后注册到Container,然后通过调用Compose方法并注入依赖。

    AttributedModelService也提供了扩展方法来直接面向组件实例编程,而不用了解到Primitive层。

    通过调用扩展方法ComposeParts(CompositionContainer, Object[]),可以直接传入通过Attribute定义好Import/Export的组件实例对象。组件的依赖会自动注入,并将Export注册到Container.

  • 相关阅读:
    bootstrap添加多个模态对话框支持
    突然想写书
    几个常用的内存、CPU飙高 分析工具
    steeltoe学习
    thrift简单使用
    记一次线上Mysql数据库 宕机
    .NetCore 开发生产环境项目前的思考&&踩坑
    SOA(面向服务架构)——踩坑后反思:这样值得吗?
    ProtoBuf与Newtonsoft序列化反序列化性能对比
    SimpleInjector 简单使用
  • 原文地址:https://www.cnblogs.com/Code-life/p/7712711.html
Copyright © 2011-2022 走看看