C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入
前言:今天十一长假的第一天,本因出去走走,奈何博主最大的乐趣是假期坐在电脑前看各处堵车,顺便写写博客,有点收获也是好的。关于MEF的知识,之前已经分享过三篇,为什么有今天这篇?是因为昨天分享领域服务的时候,用到MEF的注入有参构造函数的方法,博主好奇心重,打算稍微深挖一下,这篇来对此知识点做个总结。
还是将前面三篇的目录列出来,对MEF没有了解的朋友,可以先看看:
一、知识点回顾
我们知道MEF作为IOC的方式之一,它的主要作用是解耦,MEF加上面向接口编程,可以使得你的设计更加灵活。我们知道类的构造函数是可以重载的,我们通过构造函数可以向对象传递参数。那么如果我们的MEF也需要通过构造函数传参怎么办呢?别担心,有我们神奇的ImportingConstructor为您解决。
二、代码示例
作为分享代码,博主还是打算用前面DDD里面领域服务用到的那个Demo,现学现卖嘛,O(∩_∩)O~
1、准备代码:
作为MEF的导入导出的对象,我们先来看三个仓储接口和实现
public interface IUserRepository:IRepository<TB_USERS>
{
IEnumerable<TB_USERS> GetUsersByRole(TB_ROLE oRole);
}
[Export(typeof(IUserRepository))]
public class UserRepository:EFBaseRepository<TB_USERS>,IUserRepository
{ public IEnumerable<TB_USERS> GetUsersByRole(TB_ROLE oRole)
{
throw new NotImplementedException();
}
}
public interface IRoleRepository:IRepository<TB_ROLE>
{ }
[Export(typeof(IRoleRepository))]
public class RoleRepository:EFBaseRepository<TB_ROLE>,IRoleRepository
{ }
public interface IUserRoleRepository : IRepository<TB_USERROLE>
{ }
[Export(typeof(IUserRoleRepository))]
public class UserRoleRepository : EFBaseRepository<TB_USERROLE>, IUserRoleRepository
{
}
2、构造函数传入单个参数
直接来看代码吧:
[Export(typeof(IPowerManagerDomainService))]
public class PowerManagerDomainService:IPowerManagerDomainService
{
private IUserRepository _userRepository = null;
private IRoleRepository _roleRepository = null;
private IUserRoleRepository _userroleRepository = null; [ImportingConstructor]
public PowerManagerDomainService(IUserRoleRepository oUserRoleRepository)
{
_userroleRepository = oUserRoleRepository;
}
}
为什么通过这里的ImportingConstructor特性就能将参数IUserRoleRepository oUserRoleRepository顺利传进来?还记得前面的准备代码吗,IUserRoleRepository的实现类UserRoleRepository上面标记过导出[Export(typeof(IUserRepository))],所以这里能将参数顺利导入进来。还是来看看调用代码:
[Import]
public IPowerManagerDomainService powerDomainService { get; set; }
static void Main(string[] args)
{
var oProgram = new Program();
Regisgter.regisgter().ComposeParts(oProgram);
Console.ReadKey();
}
来调试代码看看:

3、构造函数传入多个参数
其实多个参数和上面单个参数的的也没啥太大区别
[ImportingConstructor]
public PowerManagerDomainService(IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
同样要求IUserRepository 和 IRoleRepository 类型要有对应的Export。
4、构造函数参数有多个导出
上面的例子都是默认仓储的接口类型都只有一个导出的情况,当实际项目中,业务逻辑较复杂的时候,某一个接口往往存在多个实现类的导出,这种情况下我们要怎么办呢?比如IUserRepository仓储接口有两个实现类:
[Export("userRepository_A", typeof(IUserRepository))]
public class UserRepository_A:EFBaseRepository<TB_USERS>,IUserRepository
{
public IEnumerable<TB_USERS> GetUsersByRole(TB_ROLE oRole)
{
throw new NotImplementedException();
}
}
[Export("userRepository_B", typeof(IUserRepository))]
public class UserRepository_B:EFBaseRepository<TB_USERS>,IUserRepository
{
public IEnumerable<TB_USERS> GetUsersByRole(TB_ROLE oRole)
{
throw new NotImplementedException();
}
}
这种情况下,如果我们直接在构造函数里面这样写
[ImportingConstructor]
public PowerManagerDomainService(IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
肯定是会报错的。那么我们的解决方案是:
[ImportingConstructor]
public PowerManagerDomainService([Import("userRepository_A", typeof(IUserRepository))]IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
5、多个构造函数的导入
了解了上面那么多,我们还想扩展一下,我们知道构造函数是可以重载的,一个类可以有多个构造函数。那么如果我们想在多个构造函数上面同时标记ImportingConstructor特性,然后根据需要调用不同的构造函数,这样真的行吗?比如我们想这样写:
[Export(typeof(IPowerManagerDomainService))]
public class PowerManagerDomainService:IPowerManagerDomainService
{
private IUserRepository _userRepository = null;
private IRoleRepository _roleRepository = null;
private IUserRoleRepository _userroleRepository = null; [ImportingConstructor]
public PowerManagerDomainService(IUserRoleRepository oUserRoleRepository)
{
_userroleRepository = oUserRoleRepository;
} [ImportingConstructor]
public PowerManagerDomainService([Import(typeof(IUserRepository))]IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
}
到底行不行呢?我们来测一把:

愿望是美好的,但异常是残酷的!看异常的具体信息:因为未能选择构造函数进行构造。请确保该类型具有默认构造函数或有一个标记有“System.ComponentModel.Composition.ImportingConstructorAttribute”的构造函数。很显然MEF的ImportingConstructorAttribute特性不支持这种多个构造函数同时标注的情况。将ImportingConstructorAttribute转到定义,发现它也没有其他可用属性

难道是博主的需求太奇葩啦?苦思良久,仍未找到解决方案。后来博主仔细想了想,可能是侧重点的问题,MEF一般情况是和面向接口编程联系起来用的,也就是说正常情况下我们定义的是一个接口类型的变量,例如:
[Import]
public IPowerManagerDomainService powerDomainService { get; set; }
它允许你有多个接口的实现类,如果你有多个构造函数的需求,完全可以一个接口写多个实现类去做,通过导入不同的实现类去代替不同的构造函数的用法。也不知道园友有没有更好的解决方案?不吝赐教~~
C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入的更多相关文章
- C#进阶系列——MEF实现设计上的“松耦合”(二)
前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级 ...
- C#进阶系列——MEF实现设计上的“松耦合”(一)
前言:最近去了趟外地出差,介绍推广小组开发的框架类产品.推广对象是本部门在项目上面的同事——1到2年工作经验的初级程序员.在给他们介绍框架时发现很多框架设计层面的知识他们都没有接触过,甚至没听说过,这 ...
- C#进阶系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程)
序:忙碌多事的八月带着些许的倦意早已步入尾声,金秋九月承载着抗战胜利70周年的喜庆扑面而来.没来得及任何准备,似乎也不需要任何准备,因为生活不需要太多将来时.每天忙着上班.加班.白加班,忘了去愤,忘了 ...
- MEF实现设计上的“松耦合”
C#进阶系列——MEF实现设计上的“松耦合”(二) 前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能 ...
- MEF实现设计上的“松耦合”(一)
1.什么是MEF 先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展, ...
- MEF实现设计上的“松耦合”(三)
1.面向接口编程:有一定编程经验的博友应该都熟悉或者了解这种编程思想,层和层之间通过接口依赖,下层不是直接给上层提供服务,而是定义一组接口供上层调用.至于具体的业务实现,那是开发中需要做的事情,在项目 ...
- MEF实现设计上的“松耦合”(二)
介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级应用在这里就不做过多讲解,因为博主觉得这些用法只有在某些特定的环 ...
- JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象
本篇体验通过硬编码.工厂模式.构造函数来创建JavaScript对象. □ 通过硬编码创建JavaScript对象 当需要创建一个JavaScript对象时,我们可能这样写: var person = ...
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...
随机推荐
- Web(Jsp+ Servlet)开发中如何解决中文乱码问题
1.中文乱码的成因 编码的字符集和解码的字符集不一致. 2.web开发过程中可能出现的乱码的位置及解决方案 ①request乱码 在向服务器传递数据时,所传递的中文有可能出现乱码. post请求(协议 ...
- 又到周末了,我们一起来研究【浏览器如何检测是否安装app】吧
前言 扯淡 这个月比较倒霉,我送了女朋友一台笔记本电脑作为生日礼物,结果15天一过电脑就坏了,悲剧的我还把电脑盒子给扔了!淘宝不给换更不给退 于是被女朋友臭骂了一过星期后,今天本来在公司有任务的,但是 ...
- 探讨webapp的SEO难题(上)
前言 网络蜘蛛无法解析javascript,至少百度是不能的,神马搜索差的更远,而我们的webapp的渲染展示完全由javascript驱动 所以蜘蛛访问webapp页面会得到一个白页面,比如,我们期 ...
- 学习zepto.js(对象方法)[6]
first: 获取当前对象集合中的第一个dom元素. $("div").first(); // 返回第一个div对象(zepto对象) //相当于$("div" ...
- 协调者布局:CoordinatorLayout
layout_scrollFlag属性: scroll:需要哪个View滚动就需要设置该属性: exitUntilCollapsed:向上推动屏幕的时候滑动的部分折叠起来,只有下滑到最低端的时候折叠部 ...
- Objective-C内存管理之-引用计数
本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...
- 使用putty与SSHSecureShellClient登录远程服务器完成与本地Git项目的同步
使用软件远程登录管理服务器 今天给大家介绍两款远程登录管理服务器的软件(Putty和SSHSecureShellClient),这两款也是我在工作中经常的软件. 使用 PuTTY 远程登录管理服务器 ...
- 解决Jenkins 2.0 初始化界面卡住的问题
***************************************** *原创博客转载请注明出处,谢谢!* **************************************** ...
- 我们为什么要使用maven,公司推行maven杂谈
最近在公司内推荐使用maven,推荐一个落后于业内十年的技术,实在没什么好说的,可是没想到遇到了前所未有的阻力,总是听到各种各样的质疑,我就闹不明白了,推行这个东西是为了更规范的管理项目成果,方便大家 ...
- AjaxHelper简介
在Asp.Net MVC中提供了AjaxHelper类: Ajax.ActionLink 创建一个超链接,点击时,使用Ajax提交数据到一个指定的控制器 Ajax.RouteLink 和ActionL ...