不用Unity库,自己实现.NET轻量级依赖注入
在面向对象的设计中,依赖注入(IoC)作为一种重要的设计模式,主要用于削减计算机程序的耦合问题,相对于Java中的Spring框架来说,微软企业库中的Unity框架是目前.NET平台中运用比较广泛的依赖注入框架之一(还有的Spring.NET等)。但是对于这些“官方版本”的强大依赖注入框架,通常使用和配置都比较复杂,我个人更希望实现一种“约定胜于配置”轻量级IoC框架。
实现依赖注入主要是运用C#中的反射技术,通过配置文件,把代码的实现注入到接口中。用户只是访问接口,对于接口的实现一概不知,可以有效地对接口和实现进行解耦,在介绍代码之前,先来看一下我们的配置文件:
<appSettings>
<!--依赖注入配置-->
<add key="Domain.Entity.IRepository" value="Infrastructure.Repository"/>
</appSettings>
Domain.Entity.IRepository与Infrastructure.Repository都是.NET中的程序集(dll),其中Domain.Entity.IRepository中定义了领域模型中所需要的仓储接口,Infrastructure.Repository中定义了仓储接口的实现。领域模型需要访问数据的时候,并不是直接访问ADO或者ORM,而是通过访问Domain.Entity.IRepository中的仓储接口,再通过依赖注入把Infrastructure.Repository中的实现注入到接口中,这样就有效隔离了领域模型对数据实现的依赖,如果后期需要更换数据库或ORM框架,只需要实现另一个Infrastructure.Repository,并更新依赖注入配置即可。
下面介绍轻量级依赖注入的实现方法,先贴代码:
public sealed class DependencyInjector
{
/// <summary>
/// 根据名称和构造函数的参数加载相应的类
/// </summary>
/// <typeparam name="T">需要加载的类所实现的接口</typeparam>
/// <param name="className">类的名称</param>
/// <param name="args">构造函数的参数(默认为空)</param>
/// <returns>类的接口</returns>
public static T GetClass<T>(string className, object[] args = null) where T : class
{
//获取接口所在的命名空间
string factoryName = typeof(T).Namespace;
//通过依赖注入配置文件获取接口实现所在的命名空间
string dllName = ConfigurationManager.AppSettings[factoryName];
//获取类的全名
string fullClassName = dllName + "." + className;
//根据dll和类名,利用反射加载类
object classObject = Assembly.Load(dllName).CreateInstance(fullClassName, true, BindingFlags.Default, null, args, null, null); ;
return classObject as T;
}
}
代码中的typeof(T).Namespace,其中T是接口的类型,获取接口的命名空间以后,再通过我们的配置文件,就可以获取类的命名空间,再加上类名,通过c#的反射机制,就可以加载类的实现。也许你会说,我们只知道接口,并不知道类名是什么,别急,我们对该代码进一步进行封装:
public sealed class IoC
{
/// <summary>
/// //通过接口名称和构造函数的参数得到实现
/// </summary>
/// <typeparam name="T">接口类型</typeparam>
/// <param name="args">构造函数的参数</param>
/// <returns>接口的实现</returns>
public static T Resolve<T>(object[] args = null) where T : class
{
//获取类名
);
//通过判断fullName中是否包含`符号来判断是否是泛型
string fullName = typeof(T).FullName;
int flag = fullName.IndexOf('`');
//如果是泛型,需要特殊处理
)
{
int dot = fullName.LastIndexOf('.', flag);
//这里去掉方法名前面的点和I
className = fullName.Substring(dot + );
}
return DependencyInjector.GetClass<T>(className, args);
}
}
在这里我们就用到了上面所说的”约定胜于配置“,我们约定接口的名称是在类名的前面加上I,并且接口和实现必须是独立的程序集。如果类名是Helper,那么接口的名字就必须是IHelper,我们通过去掉接口前面的I来获得实现的类名。如果是泛型接口,还需要进行特殊的处理,这里我们通过判断类型的全名中是否包含”`“符号来判断是否泛型接口。
下面举一个使用该依赖注入的例子:
public static Book GetById(string bookID)
{
IRepository<Book> bookRep = IoC.Resolve<IRepository<Book>>();
return bookRep.GetByKeys(bookID);
}
public int GetBookCount()
{
IBookRepository bookRep = IoC.Resolve<IBookRepository>();
return bookRep.GetCount();
}
在这里我们是不知道接口的实现的,通过我们封装的IoC.Resolve方法,可以把我们配置文件中的接口实现”注入到接口“中,通过这种解耦的方式,后期我可以更加灵活地对代码进行重构。
不用Unity库,自己实现.NET轻量级依赖注入的更多相关文章
- 不用Unity库,利用.NET动态代理自己实现AOP
AOP意为面向切面的程序设计,主要表现为对不同的代码逻辑进行隔离,从而降低不同业务逻辑之间的耦合性,AOP又理解为“横切”,可以在不改变原有实现的情况下,对代码进行拦截和扩展,如果原有设计像一个瓶子, ...
- Unity轻量级依赖注入容器
一.前言 Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入.在Nuget里安装unity
- Unity文档阅读 第二章 依赖注入
Introduction 介绍Chapter 1 outlines how you can address some of the most common requirements in enterp ...
- 【Unity】微软的一款依赖注入组件
前言 前面学习了autofac这个依赖注入组件,本来是打算写在一起的,因为这个组件没打算像autofac一样详细的写,只是写下以前自己鼓捣玩搭建框架然后使用的一个依赖注入组件,并且也是进行了封装使用. ...
- 使用Unity解耦你的系统—PART3——依赖注入
继续学习Unity,在前几篇中已经将Unity的使用方法做了一个还算详细的介绍了,主要是如何通过代码及配置文件来注册对象之间的关系.Unity内置所有的生命周期管理使用介绍,及Unity的Regist ...
- 使用Unity 实现ASP.NET Web API 依赖注入
DI/IoC 的设计前面已经讲过好几次了,简单的一段话说明就是:「目标对象与外部相依的方式仅相依于 interface,而相依 interface 的 instance 透过 constructor ...
- 理解依赖注入(IOC)和学习Unity
资料1: IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection). 作用:将各层的对象以松耦合的方式组织在一 ...
- 依赖注入与Unity(一) 介绍
在你学习依赖注入和Unity之前,你需要明白你为什么要使用它们.为了明白为什么要使用它们,你应该明白依赖注入和Unity能够帮助你解决什么类型的问题.作为介绍部分,这一章不会涉及太多关于Uni ...
- 通过Unity依赖注入
前言 Unity容器的思想起始于我在为Web Client Sofitware Factory项目工作的时候,微软的patterns&practices团队已经使用依赖注入的概念好几年了在那时 ...
随机推荐
- fir.im Weekly - 2016 移动开发技术大回顾
2016 年是移动技术发展迅速的一年,认认真真回顾这一年必不可少.@移动开发前线 的 这篇 2016移动开发技术巡礼 ,精心盘点了 2016 年 移动开发技术大事件,分为 iOS/Android平台篇 ...
- Java再学习——synchronized与volatile
volatile:只保证共享资源的可见性的,任何修改都写在主存,所有线程马上就能看到,适用于新值不依赖于旧值的情形. synchronized:保证可操作的原子性一致性和可见性. volatile和s ...
- kafka的一些名词
broker.id 区kafka集群中每台机器的标识 log.dirs 日志的存放目录,这个最好不要放到/tmp目录下,因为kafka的已被消费和未被消费的数据也被当成“日志”存放到了日志目录,: l ...
- BootStrap2学习日记14----导航
<div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inne ...
- 1.4.9 DocValues
DocValues 在solr4.2以后,引入了一个令人兴奋的功能,这个功能在lucene存在已经一段时间了,但是还没有在solr中使用. 在某些方面,DocValue 是一种非常有效的索引方式. 为 ...
- Linux 查看物理内存
free -k free -m free -b man free cat /proc/meminfo
- SQL查询中的in与join效率比较
大多数情况下,程序员比较喜欢使用in来查询符合某些条件的数据,最近在查询某个角色有哪些用户的方法中,使用了in语句: ) FROM baseuser AND BaseUser.Id IN (SELEC ...
- 通用权限管理系统接口文档V4.2 版本之消息接口介绍
通用权限管理系统提供的消息接口可实现消息获取,消息发送,底层使用Redis对消息进行缓存,解决消息的并发请求对数据库的压力. 前端可以通过客户端轮询来获取最新消息,前端效果截图如下:
- 【Android 界面效果21】Android ViewPager使用详解
这是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api.而viewpager就是其中之一利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等.那如 ...
- python 基础——多重继承
原始的初始化 子类直接调用超类 __init__ 方法初始化,当形成钻石继承的时候,超类会被多次初始化,可能会有意向不到的问题: BaseClass / \ OneClass Tw ...