概述
IOC (Inversion of Control) 控制反转,大家应该都比较熟悉了、应该也都有用过,这里就不具体介绍了。自己平时也有用到过IOC,但是对它的具体实现原理只有一个模糊的概念,所以决定自己手动实现一个简单IOC。
开始
首先呢我们得知道IOC的主要作用是什么,才能开始动手写。IOC主要不就是负责创建对象以及管理生命周期嘛,那我们就开始动手啦。
比如现在有一个IAnimal接口Animal继承接口,然后就是个Call的方法。一般我们使用的时候都是IAnimal animal=new Animal(); 如果是使用第三方IOC容器实现的话,我们需要先注册一下类型才能获取到实例。
所以我们先来个最简单的仿照这个过程:
新建一个Container,然后里面有一个类型注册的方法ResgisterType和一个返回实例的方法Rerolve,还有一个存储类型的字典,具体代码如下
private static Dictionary<string, object> ContainerTypeDictionary = new Dictionary<string, object>();/// <summary> /// 注册类型 /// </summary> /// <typeparam name="IT"></typeparam> /// <typeparam name="T"></typeparam> public void ResgisterType<IT,T>() { if (!ContainerTypeDictionary.ContainsKey(typeof(IT).FullName)) ContainerTypeDictionary.Add(typeof(IT).FullName, typeof(T)); } /// <summary> /// 根据注册信息生成实例 /// </summary> /// <typeparam name="IT"></typeparam> /// <returns></returns> public IT Rerolve<IT>() { string key = typeof(IT).FullName; Type type = (Type)ContainerTypeDictionary[key]; return (IT)Activator.CreateInstance(type);
}
然后我们新建一个控制台测试一下
Container container = new Container(); container.ResgisterType<IAnimal, Animal>(); IAnimal animal= container.Rerolve<IAnimal>();
然后可以在不依赖具体对象Animal的情况下成功的创建一个animal实例。
之后我们就可以考虑复杂一点的情况了,现在我们的Animal类里没有做任何事,假如它的构造函数里依赖于另一个对象呢,这样我们的程序肯定是会报错的。比如下面这样:
public class Animal: IAnimal { public Animal(Dog dog) { } }
我们容器目前能创建的对象实例,只有通过ResgisterType方法注册过类型的,而像Animal里依赖的不能实现创建,所以这个时候就需要用到依赖注入了。
关于依赖注入与控制反转的关系,我个人的理解是:控制反转是一种设计思想,而依赖注入则是实现控制反转思想的方法。
IOC容器一般依赖注入有三种:构造函数注入、方法注入、属性注入。
那么我们就来照瓢画葫芦,实现一下构造函数注入。一般IOC容器构造函数注入是通过一个特性来识别注入的,如果没有标记特性则去找构造函数参数个数最多的,我们就按照这个思路来。
首先我们新建一个LInjectionConstructorAttribute类,只需继承Attribute就行了。
public class LInjectionConstructorAttribute :Attribute { }
然后在刚才那个Animal构造函数上标记上特性,接下来就开始写代码。
/// <summary> /// 根据注册信息生成实例 /// </summary> /// <typeparam name="IT"></typeparam> /// <returns></returns> public IT Rerolve<IT>() { string key = typeof(IT).FullName; Type type = (Type)ContainerTypeDictionary[key]; return (IT)CreateType(type); }
/// <summary> /// 根据提供的类型创建类型实例并返回 /// </summary> /// <param name="type"></param> /// <returns></returns> private object CreateType(Type type) { var ctorArray = type.GetConstructors(); if (ctorArray.Count(c => c.IsDefined(typeof(LInjectionConstructorAttribute), true)) > 0) { //获取带特性标记的构造函数参数 foreach (var cotr in type.GetConstructors().Where(c => c.IsDefined(typeof(LInjectionConstructorAttribute), true))) { var paraArray = cotr.GetParameters();//获取参数数组 if (paraArray.Length == 0) { return Activator.CreateInstance(type); } List<object> listPara = new List<object>(); foreach (var para in paraArray) { string paraKey = para.ParameterType.FullName;//参数类型名称 //从字典中取出缓存的目标对象并创建对象 Type paraTargetType = (Type)ContainerTypeDictionary[para