本文阐述IoC容器的原理包含其代码实现,先简单说下IoC容器的出现它主要用于解决那类问题;在最初人们编写代码时大量的直接依赖;造成了如果下层修改签名那么上层受到强烈的影响,项目维护的成本越来越高昂;而为了尽可能的减少上层对下层的依赖且满足SOLID原则后提出了一种解决方案,即采取服务器定位器(ServiceLocator)它类似于工厂模式,但又不同,工厂模式一般只负责对于相关服务类进行实例化;而服务定位器将对所有需要的类进行依赖(牵扯过多),但由于服务定位器需要牵扯的类越来越多,造成代码之间的“耦合度”与“圈复杂度”越来越高;所以在后期此方法被遗弃重新提出一种新的方法 即IoC;事实上服务器定位器的设计真的是一种很反人类的设计。
IoC(Inversion of Control)它着重于控制反转的概念;怎么理解这个词?即把谁的控制权反转给谁,IoC是依据SOLID中的ISP原则(接口分离)与DIP原则(依赖注入)结合而来;即调用方从直接对实现类的依赖转到依赖于接口与IoC上面;从中避免对于实现类的直接依赖,转为间接依赖。
上述提到IoC控制权方面的问题,而IoC容器的则是把实例化对象的控制权从用户层交付框架层,同时对于实例化对象过程中目标类需要依赖的对象由框架层动态注入器(依赖注入器)负责;若不可注入则抛弃对其的实例化行为;这与服务器定位器需要直接与实现类牵扯不同。
废话简单的说了一堆,OK现在进入正题,对于IoC的实现它有几类方式;但在此之前框架层需要实现IoC容器,对于IoC从理论上讲不包含IoC容器,IoC仅仅只是一种设计模式;下方列出IoC的两种实现方式
1. 反射型
2. 静态型
本人先简单的谈谈静态型的原理,静态型很好理解,即“静态实例器”与“静态注入器”根据相关的用户设置,使用不同的类实例与实例注入,然后由其对编译后的程序集内注入IL代码;由其在代码运行时直接注册实例到IoC容器内;但这类方式有一种缺点实现过于复杂(若需要在.NET平台实现需要对象至少了解IL编程),但实例化的效率是最高的。
反射注入;是基于在运行时动态反射元数据进而实例化的一种方式,这类方式从实现角度上最容易但效率最慢;如果仅仅只是应用启动时需要由IoC容器实例化是不错的选择,但如果是持续实例化则建议采取静态注入的方式。站在我的角度上,我还是认为静态注入的方式最好,但不得不说它的缺点就相对明显了;对于需要控制使用不同的实现类可能会有些麻烦;你需要关停你的应用重新配置对于程序集的静态注入;但它的效率让人垂涎~~有得就有失;在不同的场景情况下可能选择方式有所不同~从适应通用场景上看的话配置型反射注入是最佳选择。
依赖注入器一般分两种模式,一、属性注入,二、构造器注入,事实上属性注入也可以是字段注入;它是一种定义上的统称说法,而在这几类注入方式中,构造器注入是最佳的,属性注入是最差的,主要是属性注入方式它可能不太稳定,而构造器注入则相对于稳定;在下方包含一种反射型IoC容器的实现,它是采取构造器注入的方式进行
namespace PhysicalGuide.Core.DDD.Service { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; public abstract class IoC<TObject> where TObject : class { private readonly ISet<object> g_persistent = null; private readonly IDictionary<Type, object> g_relational = null; public IoC() { g_persistent = new HashSet<object>(); g_relational = new Dictionary<Type, object>(); } public static bool Invalid(Type clazz) { if (clazz == null || clazz.IsValueType) { return false; } return !typeof(IServiceLocator).IsAssignableFrom(clazz); } private object FindObject(Type type) { lock (this) { object persistent = null; if (type == null) return null; if (g_relational.TryGetValue(type, out persistent)) return persistent; persistent = g_persistent.FirstOrDefault(obj => type.IsInstanceOfType(obj)); if (persistent != null) g_relational.Add(type, persistent); return persistent; } } private Type FindInheritedType(Type type, Assembly[] assemblys) { if (type.IsInterface || type.IsAbstract) { Type inherited = assemblys.Select(i => i.GetTypes().FirstOrDefault(j => j.IsSubclassOf(type))). FirstOrDefault(i => i != null); return inherited; } return type; } private object CreateObject(Type type, Assembly[] assemblys) { lock (this) { ConstructorInfo ctor = type.GetConstructors().FirstOrDefault(); if (ctor == null) { return null; } ParameterInfo[] parameters = ctor.GetParameters(); if (!parameters.Any()) { object obj = ctor.Invoke(null); g_persistent.Add(obj); return obj; } else { object[] args = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameter = parameters[i]; Type inherited = FindInheritedType(parameter.ParameterType, assemblys); if (inherited == null) { inherited = parameter.ParameterType; } object push = FindObject(inherited); if (push == null) { push = CreateObject(inherited, assemblys); } if (push == null) { return null; } args[i] = push; } object obj = ctor.Invoke(args); g_persistent.Add(obj); return obj; } } } public virtual bool Register(object obj) { if (obj == null) throw new ArgumentNullException(); lock (this) { return g_persistent.Add(obj); } } public virtual bool Register(Type type, Assembly[] assemblys) { return Resolve(type, assemblys) != null; } public virtual bool Register(Type type) { if (type == null) throw new ArgumentNullException(); return Register(type, new[] { type.Assembly }); } public virtual bool Register<T>() { return Register(typeof(T)); } public virtual bool Register<T>(Assembly[] assemblys) { return Register(typeof(T), assemblys); } public virtual object Get(Type type) { if (type == null) throw new ArgumentNullException(); return FindObject(type); } public virtual T Get<T>() { object obj = Get(typeof(T)); if (obj == null) return default(T); return (T)obj; } protected virtual object Resolve(Type type) { if (type == null) throw new ArgumentNullException(); return Resolve(type, new[] { type.Assembly }); } private void CheckAssmeblyAndThrowEmpty(Assembly[] assemblys) { if (assemblys == null) throw new ArgumentNullException(); if (assemblys.Length <= 0) throw new ArgumentException(); if (assemblys.Where(i => i == null).Any()) throw new ArgumentNullException(); } public virtual void Load(Assembly assembly) { Load(new[] { assembly }); } public virtual void Load(Assembly[] assemblys) { lock (this) { CheckAssmeblyAndThrowEmpty(assemblys); foreach (Assembly assembly in assemblys) { foreach (Type type in assembly.GetExportedTypes()) { if (!typeof(TObject).IsAssignableFrom(type)) continue; Resolve(type, assemblys); } } } } protected virtual object Resolve(Type type, Assembly[] assemblys) { CheckAssmeblyAndThrowEmpty(assemblys); if (type == null) throw new ArgumentNullException(); if (!typeof(TObject).IsAssignableFrom(type)) throw new ArgumentException("type"); lock (this) { object obj = FindObject(type); if (obj == null) { obj = CreateObject(type, assemblys); } return obj; } } } }