上一片介绍了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.

MEF学习总结(3)---Attribute Model Programing的更多相关文章

  1. MEF学习总结(1)---总体架构

    用了很久的MEF框架来做依赖注入,最近想把它的原理和机构总结一下,主要包括如下几个方面: 1. 总体架构 2. .Net Composition Primitive 3. Attribute Mode ...

  2. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  3. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  4. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  5. C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

    上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...

  6. C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

    在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...

  7. C#可扩展编程之MEF学习

    MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...

  8. [转]学习C#:Attribute与Property

    一.什么是Attribute 先看下面的三段代码: 1.自定义Attribute类:VersionAttribute [AttributeUsage(AttributeTargets.Class)] ...

  9. AngularJs学习笔记--Understanding the Model Component

    原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular文档讨论的上下文中,术语“model”可以 ...

随机推荐

  1. 【转】SQL SERVER 2005中如何获取日期(一个月的最后一日、上个月第一天、最后一天、一年的第一日等等)

    在网上找到的一篇文章,相当不错哦O(∩_∩)O~ //C#本周第一天            int dayOfWeek = Convert.ToInt32(DateTime.Now.DayOfWeek ...

  2. Linux下记录所有用户的登录和操作日志

    Linux下记录所有用户的登录和操作日志   一般我们可以用history命令来查看用户的操作记录,但是这个命令不能记录是哪个用户登录操作的,也不能记录详细的操作时间,且不完整:所以误操作而造成重要的 ...

  3. ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

    经典权限解决方案 1.权限简介 一般的管理系统都需要对用户的操作进行一定的限制,有的用户可以有许多操作,有的则有少量的操作.这样就需要一个授权机制,基于角色的授权机制描述了某个角色拥有一定数量的操作授 ...

  4. hdu 6040 Hints of sd0061(stl: nth_element(arr,arr+k,arr+n))

    Hints of sd0061 Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  5. JSP里的<c:if>不起作用[待解答]

    JSP页面的部分代码如下: 下面的title作为请求参数,shoppingCart作为session范围域的属性. 问题1: 如果去掉<c:if>的判断条件,第一行打印:可以正常显示出来, ...

  6. .net 枚举(Enum)使用总结

    在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,性别只有男跟女等等.如果把这些量说明为整型.字符型或其它类型显然是不妥当的.为此,C#提供了一种称为“ ...

  7. linux 下 iscsi的简单使用

      一.准备工作 1.1.(服务端和客户端都需要设置) 系统使用的是CentOS6.8 禁用防火墙: 查看状态:# service iptables status 停止:# systemctl sto ...

  8. idea解决mybatis逆向工程

    1.pom.xml <?xml version="1.0" encoding="UTF-8"?><project xmlns="ht ...

  9. Android架构设计之MVP分析

    转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51471280

  10. 我也说说Emacs吧(3) - 文件基本操作

    Spacemacs文件基本操作 有了前两讲的积累,我们知道了: 1. 我们既要学习emacs的操作,也要学习vi的操作 2. emacs是一个可扩展的平台,我们并不是从头配置,而是使用一套成熟的集成方 ...