1.概述
IOC:有很多人把控制反转和依赖注入混为一谈,虽然在某种意义上来看他们是一体的,但好像又有些不同。
1. IOC(控制反转)是一个控制容器,DI(依赖注入)就是这个容器的运行机制。
2. IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。
关于Ioc的框架有很多,比如astle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用 Nuget 添加 Unity ,
也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll。
2.代码演示
a. 先介绍常规做法,代码比较简单,稍微看一下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public interface IBaseRepository { void DoSomething(); } public interface IRespository : IBaseRepository { } public interface IUserRepository : IBaseRepository { } public interface IShopRepository : IBaseRepository { } public class Repository : IRespository { public void DoSomething() { Console.WriteLine("I am a Repository"); } } public class UserRepository : IUserRepository { public void DoSomething() { Console.WriteLine("I am a UserRepository"); } } public class ShopRepository : IShopRepository { public void DoSomething() { Console.WriteLine("I am a ShopRepository"); } } public interface ITestService { void DoSomething(); } public class TestService : ITestService { private IRespository respository; ////// 构造注入 /// /// public TestService(IRespository _respository) { this.respository = _respository; } ////// 属性注入 /// [Dependency] public IUserRepository UserRepository { get; set; } public IShopRepository ShopRepository { get; set; } ////// 方法注入 /// /// [InjectionMethod] public void SetShopRepository(IShopRepository _shopRepository) { this.ShopRepository = _shopRepository; } public void DoSomething() { respository.DoSomething(); UserRepository.DoSomething(); ShopRepository.DoSomething(); } } class Program { static void Main(string[] args) { UnityContainer container = new UnityContainer(); container.RegisterType(); container.RegisterType (); container.RegisterType (); container.RegisterType (); TestService testService = container.Resolve () as TestService; testService.DoSomething(); } }
b. 还有一种是配置文件做法
这个是配置文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
对应的代码也得改改:
InitializeComponent(); //创建容器 UnityContainer container = new UnityContainer(); UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection; configuration.Configure(container, "defaultContainer"); //通过Resolve方法返回的是一个类型为TestService的对象,该对象的三个属性被进行了有效的初始化。 //这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性IRespository)、属性注入(属性IUserRepository)和方法注入(属性IShopRepository) TestService t = container.Resolve () as TestService ; if (null != t) { t.DoSomething(); }
3. Unity的生命周期
Unity有三种注入方式,构造,属性和方法注入,Unity注入也有自己的生命周期(默认瞬时生命周期:每次都是构造一个新的),下面就介绍下生命周期。
IUnityContainer container = new UnityContainer();//默认瞬时生命周期,每次都是构造一个新的container.RegisterType(new TransientLifetimeManager());//每线程生命周期管理器,就是保证每个线程返回同一实例container.RegisterType (new PerThreadLifetimeManager());//容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象container.RegisterType (new ContainerControlledLifetimeManager());//分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例,针对某个层单例//不过与ContainerControlledLifetimeManager不同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器和子容器所维护的对象的生命周期是由各自的容器来管理container.RegisterType (new HierarchicalLifetimeManager());//这个生命周期是为了解决循环引用而重复引用的生命周期container.RegisterType (new PerResolveLifetimeManager());//外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁掉。//在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象container.RegisterType (new ExternallyControlledLifetimeManager());
4. 自己手动实现简单IOC容器
怎么自己实现一个简单的IOC容器呢?本次只实现一个简单的版本,生命周期只实现了三种,分别是瞬时,单例和线程单例。
a.首先定义一个生命周期的枚举 :
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public enum LifeTimeType { ////// 瞬时 /// Transient, ////// 单例 /// Singleton, ////// 线程单例 /// PerThread }
b. 定义一个保存注册映射信息的对象:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public class RegisterInfo { ////// 目标类型 /// public Type TargetType { get; set; } ////// 生命周期 /// public LifeTimeType LifeTime { get; set; } }
c. 定义三个Attribute,直接写一起了:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class DependencyAttribute : Attribute { public LifeTimeType _lifeTimeType { get; set; } public DependencyAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient) { this._lifeTimeType = lifeTimeType; } } [AttributeUsage(AttributeTargets.Constructor)] public class InjectionConstructorAttribute : Attribute { public InjectionConstructorAttribute() { } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class InjectionMethodAttribute : Attribute { private LifeTimeType _lifeTimeType { get; set; } public InjectionMethodAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient) { this._lifeTimeType = lifeTimeType; } }
d. 定义一个容器的接口:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public interface IIOCContainer { void RegisterType(LifeTimeType lifeTimeType = LifeTimeType.Transient); T Resolve (); }
e. 实现该接口的方法,这是整个容器的关键代码,代码比较长,写的可能有错误,欢迎指正:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public class IOCContainer : IIOCContainer { ////// 缓存注入的配置 /// private DictionaryContainerDictionary = new Dictionary (); /// /// 缓存起来,类型的对象实例 /// private DictionaryTypeObjectDictionary = new Dictionary (); public void RegisterType (LifeTimeType lifeTimeType = LifeTimeType.Transient) { ContainerDictionary.Add(typeof(TFrom).FullName, new RegisterInfo() { TargetType = typeof(TTo), LifeTime = lifeTimeType }); } public T Resolve () { RegisterInfo info = ContainerDictionary[typeof(T).FullName]; Type type = ContainerDictionary[typeof(T).FullName].TargetType; T result = default(T); result = (T)CreateTypeByRegisterType(info, type); return result; } private object CreateObject(Type type) { ConstructorInfo[] ctorArray = type.GetConstructors(); ConstructorInfo ctor = null; if (ctorArray.Count(c => c.IsDefined(typeof(InjectionConstructorAttribute), true)) > 0) { ctor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(InjectionConstructorAttribute), true)); } else { ctor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); } List
以上代码经过测试,可以使用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public interface IImitateScene { void DoSomeThing(); } public class ImitateScene: IImitateScene { private IUserService userService; public ImitateScene(IUserService _userService) { this.userService = _userService; } [Dependency(LifeTimeType.Transient)] public IShopService ShopService { get; set; } public IStoreService StoreService { get; set; } [InjectionMethod(LifeTimeType.Transient)] public void SetStoreService(IStoreService _storeService) { this.StoreService = _storeService; } public void DoSomeThing() { this.userService.DoSomeThing(); this.StoreService.DoSomeThing(); this.ShopService.DoSomeThing(); } }
附上项目图,项目结构只为了测试,未做过设计,嘿嘿
测试结果:
基本代码就在这里了,还有很多功能未完善,后续有时间会努力研究完善它,造造轮子。