博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅聊IOC
阅读量:7242 次
发布时间:2019-06-29

本文共 11794 字,大约阅读时间需要 39 分钟。

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.  先介绍常规做法,代码比较简单,稍微看一下:

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(); } }
View Code

    b. 还有一种是配置文件做法

        这个是配置文件:

View Code

      对应的代码也得改改:

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.首先定义一个生命周期的枚举 :

public enum LifeTimeType    {        ///         /// 瞬时        ///         Transient,        ///         /// 单例        ///         Singleton,        ///         /// 线程单例        ///         PerThread    }
View Code

 

     b. 定义一个保存注册映射信息的对象:

public class RegisterInfo    {        ///         /// 目标类型        ///         public Type TargetType { get; set; }        ///         /// 生命周期        ///         public LifeTimeType LifeTime { get; set; }    }
View Code

 

     c. 定义三个Attribute,直接写一起了:

[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;        }    }
View Code

 

     d. 定义一个容器的接口:

public interface IIOCContainer    {        void RegisterType
(LifeTimeType lifeTimeType = LifeTimeType.Transient); T Resolve
(); }
View Code

 

     e. 实现该接口的方法,这是整个容器的关键代码,代码比较长,写的可能有错误,欢迎指正:

public class IOCContainer : IIOCContainer    {        ///         /// 缓存注入的配置        ///         private Dictionary
ContainerDictionary = new Dictionary
(); ///
/// 缓存起来,类型的对象实例 /// private Dictionary
TypeObjectDictionary = 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
paraList = new List(); foreach (var parameter in ctor.GetParameters()) { Type paraType = parameter.ParameterType; RegisterInfo info = ContainerDictionary[paraType.FullName]; Type targetType = info.TargetType; object para = null; para = CreateTypeByRegisterType(info, targetType); //递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数 paraList.Add(para); } object objType = Activator.CreateInstance(type, paraList.ToArray()); //属性注入 var properties = type.GetProperties() .Where(p => p.IsDefined(typeof(DependencyAttribute), false)).ToList(); foreach (var item in properties) { var customAttributes = item.GetCustomAttributes(typeof(DependencyAttribute), false) as DependencyAttribute[]; if (customAttributes != null) { Type t = item.PropertyType; RegisterInfo info = ContainerDictionary[t.FullName]; info.LifeTime = customAttributes.FirstOrDefault()._lifeTimeType; var value = CreateObject(info.TargetType); item.SetValue(objType, value); } } //字段注入 var filds = type.GetFields().Where(f => f.IsDefined(typeof(DependencyAttribute), false)).ToList(); foreach (var fild in filds) { var attribute = fild.GetCustomAttribute(typeof(DependencyAttribute)) as DependencyAttribute; if (attribute != null) { Type t = fild.DeclaringType; RegisterInfo info = ContainerDictionary[t.FullName]; info.LifeTime = attribute._lifeTimeType; var value = CreateObject(info.TargetType); fild.SetValue(objType, value); } } //方法注入 var methods = type.GetMethods().Where(m => m.IsDefined(typeof(InjectionMethodAttribute), false)).ToList(); List paramrterList = new List(); foreach (var item in methods) { var attribute = item.GetCustomAttribute(typeof(InjectionMethodAttribute)) as InjectionMethodAttribute; if (attribute != null) { var parameters = item.GetParameters(); foreach (var parameter in parameters) { var paraType = parameter.ParameterType; RegisterInfo info = ContainerDictionary[paraType.FullName]; Type targetType = info.TargetType; object para = CreateTypeByRegisterType(info, targetType); //递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数 paramrterList.Add(para); } item.Invoke(objType, paramrterList.ToArray()); } } return objType; } private static readonly object obj = new object(); /// /// 根据注入类别创建对象 /// /// /// ///
private object CreateTypeByRegisterType(RegisterInfo info, Type targetType) { object para = null; switch (info.LifeTime) { case LifeTimeType.Transient: para = this.CreateObject(targetType); break; case LifeTimeType.Singleton: //需要线程安全 双if+lock if (para == null) { lock (obj) { if (this.TypeObjectDictionary.ContainsKey(targetType)) { para = this.TypeObjectDictionary[targetType]; } else { if (para == null) { para = this.CreateObject(targetType); this.TypeObjectDictionary[targetType] = para; } } } } break; case LifeTimeType.PerThread: //线程单例:线程槽,把数据存在这里 { string key = targetType.FullName; object oValue = CallContext.GetData(key); if (oValue == null) { para = this.CreateObject(targetType); CallContext.SetData(key, para); } else { para = oValue; } } break; default: throw new Exception("wrong LifeTime"); } return para; } }
View Code

 

 

以上代码经过测试,可以使用。

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();        }    }
View Code

 附上项目图,项目结构只为了测试,未做过设计,嘿嘿

测试结果:

基本代码就在这里了,还有很多功能未完善,后续有时间会努力研究完善它,造造轮子。

 

转载于:https://www.cnblogs.com/bobo-pcb/p/10680773.html

你可能感兴趣的文章
Android应用实例之---使用Linkify + 正则式区分微博文本链接及跳转处理
查看>>
关于uploadify使用的一些小问题
查看>>
shell seq
查看>>
docker技术剖析--数据卷 for centos7.2
查看>>
linux环境安装node.js环境和pm2
查看>>
跳槽的时候如何和招聘方谈薪水
查看>>
mysql5.7的主从复制+读写分离
查看>>
周工作不得超过40小时
查看>>
synchronized块
查看>>
maven 引入 本地 jar
查看>>
Struts2.1.6+Spring2.5.6+Hibernate3.3.1全注解实例详解(四)
查看>>
服务器RAID6三块硬盘离线 数据丢失的恢复过程
查看>>
Sql Server数据库由于未知原因丢失的恢复方法
查看>>
dsp技术
查看>>
Win7出现临时用户解决办法
查看>>
HttpClient 和 HttpUrlConnection 简单封装
查看>>
windows redis 集群搭建(三)
查看>>
[软考]关键路径法CPM详细解释及应用,实例讲解收集(信息系统项目管理师-时间管理)...
查看>>
基于Cubieboard的HuLuduino硬件计划和Sunduino软件计划启动
查看>>
esxi虚拟机无法正常启动
查看>>