MEF 基础简介 二
MEF的导出(Export)和导入(Import)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[Import("MusicBook")]
public IBookService Service { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Service != null)
{
Console.WriteLine(pro.Service.GetBookName());
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
然后修改MusicBook的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
}
}
注意,标红的是改动过的地方,其他地方的代码没有变,上一次我们使用的是Export的方法是[Export(typeof(IBookService))],这次前面多了一个参数,没错,这个就是一个契约名,名字可以随便起,而且可以重复,但是如果名字乱起,和其他DLL中的重复,到时候会导致程序出现很多Bug,最好按照一定的规范去起名字。
这里有了契约名以后,导入(Import)时就要指定的契约名,否则将无法找到MusicBook,Export还有一个方法是[Export("Name")],这个方法只指定了契约名,没有指定导出类型,那么默认的导出类型是object类型,在导入时导出到的对象就要为object类型,否则将匹配不到那个组件。
到现在,我们只写了一个接口和一个实现类,导出的也是一个类,下面我们多添加几个类来看看会怎么样,为了方便大家测试,我把实现接口的类写在一个文件里面,新加几个类后,的MusicBook类文件代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
} [Export("MusicBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MathBook";
}
} [Export("MusicBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "HistoryBook";
}
} }
这里添加两个类,HistoryBook和MathBook,都继承自IBookService接口,注意他们的契约名都相同,都为MusicBook,后面再详细的说这个问题,修改后的program的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<IBookService> Services { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
Console.WriteLine(s.GetBookName());
}
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
这里需要注意的是标红的两行代码,[ImportMany("MusicBook")]还有下面的声明变成了IEnumerable<>,因为要导出多个实例,所以要用到集合,下面采用foreach遍历输出,运行的结果如下图:

导入和导出时都不写契约名,就会全部导出。那么写契约名有什么好处呢?下面我们用代码说明问题,修改实现类的契约名如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
} [Export("MathBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MathBook";
}
} [Export("HistoryBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "HistoryBook";
}
} }
现在三个类的契约名都不相同了,其他的代码不动,再次运行程序看看,是不是现在只输出MusicBook了,同理,修改[Import("Name")]中的契约名称,就会导入指定含有名称的类,契约名可以重复,这一以来,我们就可以用契约名给类进行分类,导入时可以根据契约名来导入。
注意:IEnumerable<T>中的类型必须和类的导出类型匹配,如类上面标注的是[Exprot(typeof(object))],那么就必须声明为IEnumerable<object>才能匹配到导出的类。
例如:我们在类上面标注[Export("Book")],我们仅仅指定了契约名,而没有指定类型,那么默认为object,此时还用IEnumerable<IBookService>就匹配不到。
那么,这种情况就要在输出是进行强制类型转换,代码如下:
[Export("MusicBook")]
public class MusicBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MusicBook";
}
}
program中的代码改变如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<object> Services { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
var ss = (IBookService)s;
Console.WriteLine(ss.GetBookName());
}
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
MEF 基础简介 二的更多相关文章
- MEF 基础简介 一
前言 小编菜鸟级别的程序员最近感慨颇多,经历了三五春秋深知程序路途遥远而我沧海一粟看不到的尽头到不了的终点何处是我停留的驿站.说了段废话下面进入正题吧! 什么是MEF? MEF:全称Managed E ...
- MEF 基础简介 四
前言 前面讲解了MEF的引用方法,接口的导入导出,类属性的导入导出和集合的导出用法其实大家可以看到基本上大同小异的. MEF的延迟加载 我们知道当装配一个组件的时候,当前组件里面的所有的Import的 ...
- MEF 基础简介 三
MEF导出类的方法和属性 首先来说导出属性,因为这个比较简单,和导出类差不多,先来看看代码,主要看我加注释的地方,MusicBook.cs中的代码如下: using System; using Sys ...
- Python基础-简介二
一.变量类型 变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据类型,这些 ...
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
Django基础七之Ajax 本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 一 Ajax简介 ...
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
{Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) Django基础七之 ...
- 现代3D图形编程学习-基础简介(2) (译)
本书系列 现代3D图形编程学习 基础简介(2) 图形和渲染 接下去的内容对渲染的过程进行粗略介绍.遇到的部分内容不是很明白也没有关系,在接下去的章节中,会被具体阐述. 你在电脑屏幕上看到的任何东西,包 ...
- 现代3D图形编程学习-基础简介(1) (译)
本书系列 现代3D图形编程学习 基础简介 并不像本书的其他章节,这章内容没有相关的源代码或是项目.本章,我们将讨论向量,图形渲染理论,以及OpenGL. 向量 在阅读这本书的时候,你需要熟悉代数和几何 ...
- JVM 内部原理(七)— Java 字节码基础之二
JVM 内部原理(七)- Java 字节码基础之二 介绍 版本:Java SE 7 为什么需要了解 Java 字节码? 无论你是一名 Java 开发者.架构师.CxO 还是智能手机的普通用户,Java ...
随机推荐
- 关于http与https的注意点
背景:在一次项目生产上线中遇到地址在IOS版本的app中打不开或者接口请求不返回的情况,在安卓机和PC上表现正常,经排查,问题出在http请求上,原因详解 在早期PC上和安卓手机上比较不严格,在htt ...
- Linux编程之fork函数
在Linux中,fork函数的功能就是在一个进程中创建一个新的进程,当前调用fork函数的进程就是产生的新进程的父进程,新进程在以下也称为子进程.在新进程生成之后就会在系统中开始执行. 函数原型:pi ...
- POJ 1067 威佐夫博弈
点这里去看题 套公式,判断是否为奇异组合 #include<stdio.h> #include<algorithm> #include<math.h> #inclu ...
- echarts 调整图表 位置 的方法
###内部图表大小是与div容器大小位置相关的,如果想调整图表大小位置,调整div的属性就可以了### ###如果是想调整图表与div间上下左右留白,则设置grid属性就可以了### 如图所示: 具体 ...
- nginx三种安装方法(转载)
Nginx是一款轻量级的网页服务器.反向代理服务器.相较于Apache.lighttpd具有占有内存少,稳定性高等优势.它最常的用途是提供反向代理服务. 1.安装包编译安装 2.yum源安装 3.使用 ...
- Python序列结构--元组
元组:轻量级列表 元组创建于元素访问 >>> x = (1, 2, 3)>>> type(x)<class 'tuple'>>>> x ...
- 背水一战 Windows 10 (98) - 关联启动: 使用外部程序打开一个文件, 使用外部程序打开一个 Uri
[源码下载] 背水一战 Windows 10 (98) - 关联启动: 使用外部程序打开一个文件, 使用外部程序打开一个 Uri 作者:webabcd 介绍背水一战 Windows 10 之 关联启动 ...
- TextView的跑马灯效果实现
TextView的跑马灯效果实现 问题描述 当文字内容过长,但是只允许显示一行时,可以将文字显示为跑马灯效果,即文字滚动显示. 代码实现 第一种方法实现 先查询TextView控件的属性,得到以下信息 ...
- PHP7 ?:和??的区别
?:和??是PHP添加的新特性,我们可以通过下面的代码来理解 $z = $x ?? $y; //等价于下面 $z = isset($x) ? $x : $y; $z = $x ?: $y; //等价于 ...
- 开源深度学习架构Caffe
Caffe 全称为 Convolutional Architecture for Fast Feature Embedding,是一个被广泛使用的开源深度学习框架(在 TensorFlow 出现之前一 ...