简述控制反转ioc_IOC控制反转、Unity简介

参考博客地址:

这篇文章主要介绍.NET Framework下面的IOC以及Unity的使用,下一篇文章介绍.NET Core下面自带的容器IServiceCollection以及Autofac的使用https://www.cnblogs.com/taotaozhuanyong/p/11562184.html

IOC(Inverse of Control),控制反转。

说到IOC,就不得不提DI(Dependency Injection),依赖注入

IOC是目标效果,需要DI依赖注入的手段。

分层架构时这些是必须的,可以划分边界独立演化,也方便分工,促进代码复用。。

依赖倒置原则DIP:

系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖。依赖抽象而不是依赖细节。在A勒种调用了B类,A类就是高层,B类就是低层。

面向抽象:

1、一个方法满足多种类型

2、支持下层的扩展。

下面有三种创建一个对象的方式:

AndroidPhone phone = new AndroidPhone();//1 全是细节

IPhone phone= new AndroidPhone();//2 左边抽象右边细节

IPhone phone= ObjectFactory.CreatePhone();//3 封装转移

///

///简单工厂+配置文件+反射///

public classObjectFactory

{public staticIPhone CreatePhone()

{string classModule = ConfigurationManager.AppSettings["iPhoneType"];

Assembly assemly= Assembly.Load(classModule.Split(',')[1]);

Type type= assemly.GetType(classModule.Split(',')[0]);return (IPhone)Activator.CreateInstance(type);//无参数构造函数

}public staticIPhone CreatePhone(IBaseBll iBLL)

{string classModule = ConfigurationManager.AppSettings["iPhoneType"];

Assembly assemly= Assembly.Load(classModule.Split(',')[1]);

Type type= assemly.GetType(classModule.Split(',')[0]);return (IPhone)Activator.CreateInstance(type, new object[] { iBLL });

}

}

在App.config下面配置节点:

只有抽象,没有细节,好处是可扩展。

IOC控制反转:

传统开发,上端依赖(调用/指定)下端对象,这个样子会有依赖。控制反转就是把对下端对象的依赖转移到第三方容器(工厂+配置文件+反射),能够让程序拥有更好的扩展性。

下面出现一个问题:

构造A对象,但是A依赖于B对象,那就先构造B,如果B又依赖C,再构造C。。。。。。

IDAL.IBaseDAL baseDAL = newDAL.BaseDAL();

IBLL.IBaseBll baseBll= newBLL.BaseBll(baseDAL);

IPhone phone= ObjectFactory.CreatePhone(baseBll);

现在这个问题已经暴露了,下面开始了DI,依赖注入,就能做到构造某个对象时,将依赖的对象自动初始化并注入。

IOC是目标效果,需要DI依赖注入的手段。

DI依赖注入:

三种方式注入:构造函数注入、属性注入、方法注入(按照时间顺序)

[Dependency]//属性注入

[Dependency]//属性注入

public IMicrophone iMicrophone { get; set; }

[InjectionConstructor]//构造函数注入,默认找参数最多的构造函数,方法注入不加这个特性也是可以的,可以不用特性,可以去掉对容器的依赖

[InjectionConstructor]//构造函数注入:默认找参数最多的构造函数

publicApplePhoneUpdate(IHeadphone headphone)

{this.iHeadphone =headphone;

Console.WriteLine("{0} 带参数构造函数", this.GetType().Name);

}

[InjectionMethod]//方法注入

[InjectionMethod]//方法注入

public voidInit(IPower power)

{this.iPower =power;

}

如何使用Unity容器?

1、安装Unity

2、容器三部曲:

实例化容器、注册类型、获取实例

3、项目版本和服务处的版本要一直。

下面是Iphone与AndroidPhone的定义:

public interfaceIPhone

{voidCall();

IMicrophone iMicrophone {get; set; }

IHeadphone iHeadphone {get; set; }

IPower iPower {get; set; }

}public classAndroidPhone : IPhone

{public IMicrophone iMicrophone { get; set; }public IHeadphone iHeadphone { get; set; }public IPower iPower { get; set; }//public AndroidPhone()//{//Console.WriteLine("{0}构造函数", this.GetType().Name);//}

publicAndroidPhone(AbstractPad pad, IHeadphone headphone)

{

Console.WriteLine("{0}构造函数", this.GetType().Name);

}//[ElevenInjectionConstructor]

publicAndroidPhone(AbstractPad pad)

{

Console.WriteLine("{0}构造函数", this.GetType().Name);

}publicAndroidPhone(IBaseBll baseBll)

{

Console.WriteLine("{0}构造函数", this.GetType().Name);

}public voidCall()

{

Console.WriteLine("{0}打电话", this.GetType().Name); ;

}

}

View Code

IUnityContainer container = new UnityContainer();//1 实例化容器

container.RegisterType();//2 注册类型

IPhone iphone = container.Resolve();//3 获取实例

我们来看一下Unity下面RegisterType方法里面的泛型约束:

还有一个方法:

IUnityContainer container = new UnityContainer();//1 实例化容器

container.RegisterInstance(newApplePadChild());

AbstractPad abstractPad= container.Resolve();

后遭的时候,有依赖:

下面来解决这个问题:但是要保持Unity版本一致

下面是一些注册时要依赖的类型

public interfaceIHeadphone

{

}public classHeadphone : IHeadphone

{publicHeadphone(IMicrophone microphone)

{

Console.WriteLine("Headphone 被构造");

}

}public interfaceIMicrophone

{

}public classMicrophone : IMicrophone

{publicMicrophone(IPower power)

{

Console.WriteLine("Microphone 被构造");

}

}public interfaceIPower

{

}public classPower : IPower

{publicPower(IBLL.IBaseBll baseBll)

{

Console.WriteLine("Power 被构造");

}

}public interfaceIBaseBll

{voidDoSomething();

}public classBaseBll : IBaseBll

{private IBaseDAL _baseDAL = null;public BaseBll(IBaseDAL baseDAL, intid)

{

Console.WriteLine($"{nameof(BaseBll)}被构造。。。{id}。");this._baseDAL =baseDAL;

}public voidDoSomething()

{this._baseDAL.Add();this._baseDAL.Update();this._baseDAL.Find();this._baseDAL.Delete();

}

}public interfaceIBaseDAL

{voidAdd();voidDelete();voidUpdate();voidFind();

}public classBaseDAL : IBaseDAL

{publicBaseDAL()

{

Console.WriteLine($"{nameof(BaseDAL)}被构造。。。。");

}public voidAdd()

{

Console.WriteLine($"{nameof(Add)}");

}public voidDelete()

{

Console.WriteLine($"{nameof(Delete)}");

}public voidFind()

{

Console.WriteLine($"{nameof(Find)}");

}public voidUpdate()

{

Console.WriteLine($"{nameof(Update)}");

}

}

View Code

IUnityContainer container = newUnityContainer();

container.RegisterType();

container.RegisterType();

container.RegisterType();

container.RegisterType();

container.RegisterType();

container.RegisterType();

IPhone iphone= container.Resolve();

但凡是用到了需要的类型,都要给注入进去,不然容器怎么知道类型啊

Unity里面到底是怎么实现的?下面,自己来写一个IOC

1、最最基础简陋的版本:

public interfaceILTContainer

{void RegisterType();

T Resolve();

}///

///容器--工厂///

public classLTContainer : ILTContainer

{private Dictionary LTDic = new Dictionary();public void RegisterType()

{

LTDic.Add(typeof(TFrom).FullName, typeof(TTo));

}public T Resolve()

{

Type type= LTDic[typeof(T).FullName];return(T)Activator.CreateInstance(type);

}

}

}

调用一下:

ILTContainer container = newLTContainer();

container.RegisterType();var person = container.Resolve();

2、升级一点点

public interfaceIPerson

{

}public classStudent : IPerson

{

[LTInjectionConstructor]publicStudent(Animal animal)

{

Console.WriteLine("Student被构造了...");

}

}public abstract classAnimal

{

}public classCat : Animal

{publicCat()

{

Console.WriteLine("Animal被构造了....");

}

}

}

public interfaceILTContainer

{void RegisterType();

T Resolve();

}///

///容器--工厂///

public classLTContainer : ILTContainer

{private Dictionary LTDic = new Dictionary();public void RegisterType()

{

LTDic.Add(typeof(TFrom).FullName, typeof(TTo));

}public T Resolve()

{

Type type= LTDic[typeof(T).FullName];var ctorArray =type.GetConstructors();

ConstructorInfo ctor= null;if (ctorArray.Count(c => c.IsDefined(typeof(LTInjectionConstructorAttribute), true)) > 0)

{

ctor= ctorArray.FirstOrDefault(c => c.IsDefined(typeof(LTInjectionConstructorAttribute), true));

}else{

ctor= ctorArray.OrderByDescending(c =>c.GetParameters().Length).FirstOrDefault();

}

List paraList = new List();foreach (var item inctor.GetParameters())

{

Type paraType=item.ParameterType;

Type targetType= this.LTDic[paraType.FullName];

paraList.Add(Activator.CreateInstance(targetType));

}return(T)Activator.CreateInstance(type, paraList.ToArray());//return (T)this.CreateObject(type);

}private objectCreateObject(Type type)

{

ConstructorInfo[] ctorArray=type.GetConstructors();

ConstructorInfo ctor= null;if (ctorArray.Count(c => c.IsDefined(typeof(LTInjectionConstructorAttribute), true)) > 0)

{

ctor= ctorArray.FirstOrDefault(c => c.IsDefined(typeof(LTInjectionConstructorAttribute), true));

}else{

ctor= ctorArray.OrderByDescending(c =>c.GetParameters().Length).FirstOrDefault();

}

List paraList = new List();foreach (var parameter inctor.GetParameters())

{

Type paraType=parameter.ParameterType;

Type targetType= this.LTDic[paraType.FullName];object para = this.CreateObject(targetType);//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数

paraList.Add(para);

}returnActivator.CreateInstance(type, paraList.ToArray());

}//属性注入+方法注入?

}

调用一下:

ILTContainer container = newLTContainer();

ILTContainer container= newLTContainer();

container.RegisterType();

container.RegisterType();var person = container.Resolve();

3、再升级一点点:

继续找出targetType的构造,找出一个合适的构造函数,分别构造其参数,继续...递归

public interfaceILTContainer

{void RegisterType();

T Resolve();

}///

///容器--工厂///

public classLTContainer : ILTContainer

{private Dictionary LTDic = new Dictionary();public void RegisterType()

{

LTDic.Add(typeof(TFrom).FullName, typeof(TTo));

}public T Resolve()

{

Type type= LTDic[typeof(T).FullName];//继续找出targetType的构造函数,找出一个合适的构造函数,分别构造其参数//继续......递归

return (T)this.CreateObject(type);

}public objectCreateObject(Type type)

{

ConstructorInfo[] ctorArray=type.GetConstructors();

ConstructorInfo ctor= null;if (ctorArray.Count(c => c.IsDefined(typeof(LTContainer), true)) > 0)

{

ctor= ctorArray.FirstOrDefault(c => c.IsDefined(typeof(LTContainer), true));

}else{

ctor= ctorArray.OrderByDescending(c =>c.GetParameters().Length).FirstOrDefault();

}

List paraList = new List();foreach (var parameter inctor.GetParameters())

{

Type paraType=parameter.ParameterType;

Type targetType= this.LTDic[paraType.FullName];object para = this.CreateObject(targetType);//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数

paraList.Add(para);

}returnActivator.CreateInstance(type, paraList.ToArray());

}//属性注入+方法注入?

}

生命管理周期:

IUnityContainer container = new UnityContainer();

默认瞬时生命周期:每次都是构造一个新的

container.RegisterType();

container.RegisterType(new TransientLifetimeManager());

全局单例:全局就只有一个该类型实例

非强制性,只有通过容器获取才是单例;项目中一般推荐容器单例而不是自己写单例

container.RegisterType(newSingletonLifetimeManager());

AbstractPad pad1= container.Resolve();

AbstractPad pad2= container.Resolve();

Console.WriteLine(object.ReferenceEquals(pad1, pad2));

线程单例:同一个线程就只有一个实例,不同线程就是不同实例

container.RegisterType(newPerThreadLifetimeManager());

AbstractPad pad1= null;

AbstractPad pad2= null;

AbstractPad pad3= null;

Action act1= new Action(() =>{

pad1= container.Resolve();

Console.WriteLine($"pad1由线程id={Thread.CurrentThread.ManagedThreadId}");

});var result1 = act1.BeginInvoke(null, null);

Action act2= new Action(() =>{

pad2= container.Resolve();

Console.WriteLine($"pad2由线程id={Thread.CurrentThread.ManagedThreadId}");

});var result2 = act2.BeginInvoke(t =>{

pad3= container.Resolve();

Console.WriteLine($"pad3由线程id={Thread.CurrentThread.ManagedThreadId}");

Console.WriteLine($"object.ReferenceEquals(pad2, pad3)={object.ReferenceEquals(pad2, pad3)}");

},null);

act1.EndInvoke(result1);

act2.EndInvoke(result2);

Console.WriteLine($"object.ReferenceEquals(pad1, pad2)={object.ReferenceEquals(pad1, pad2)}");

//ExternallyControlledLifetimeManager 外部可释放单例

//PerResolveLifetimeManager 循环引用

自己写的容器里面,加上生命周期:

public interfaceIBingleContainer

{void RegisterType(LifeTimeType lifeTimeType =LifeTimeType.Transient);

T Resolve();

}///

///容器--工厂///

public classBingleContainer : IBingleContainer

{private Dictionary BingleContainerDictionary = new Dictionary();///

///缓存起来,类型的对象实例///

private Dictionary TypeObjectDictionary = new Dictionary();///

///

///

///

///

/// 默认参数,不传递就是Transient

public void RegisterType(LifeTimeType lifeTimeType =LifeTimeType.Transient)

{

BingleContainerDictionary.Add(typeof(TFrom).FullName, newRegisterInfo()

{

TargetType= typeof(TTo),

LifeTime=lifeTimeType

});

}public T Resolve()

{

RegisterInfo info= BingleContainerDictionary[typeof(T).FullName];

Type type= BingleContainerDictionary[typeof(T).FullName].TargetType;

T result= default(T);switch(info.LifeTime)

{caseLifeTimeType.Transient:

result= (T)this.CreateObject(type);break;caseLifeTimeType.Singleton:if (this.TypeObjectDictionary.ContainsKey(type))

{

result= (T)this.TypeObjectDictionary[type];

}else{

result= (T)this.CreateObject(type);this.TypeObjectDictionary[type] =result;

}break;caseLifeTimeType.PerThread://怎么保证用线程校验呢? 线程槽,把数据存在这里

{string key =type.FullName;object oValue =CallContext.GetData(key);if (oValue == null)

{

result= (T)this.CreateObject(type);

CallContext.SetData(key, result);

}else{

result=(T)oValue;

}

}break;default:throw new Exception("wrong LifeTime");

}returnresult;

}private objectCreateObject(Type type)

{

ConstructorInfo[] ctorArray=type.GetConstructors();

ConstructorInfo ctor= null;if (ctorArray.Count(c => c.IsDefined(typeof(BingleInjectionConstructorAttribute), true)) > 0)

{

ctor= ctorArray.FirstOrDefault(c => c.IsDefined(typeof(BingleInjectionConstructorAttribute), true));

}else{

ctor= ctorArray.OrderByDescending(c =>c.GetParameters().Length).FirstOrDefault();

}

List paraList = new List();foreach (var parameter inctor.GetParameters())

{

Type paraType=parameter.ParameterType;

RegisterInfo info=BingleContainerDictionary[paraType.FullName];

Type targetType=info.TargetType;//object para = this.CreateObject(targetType);

object para = null;#region {switch(info.LifeTime)

{caseLifeTimeType.Transient:

para= this.CreateObject(targetType);break;caseLifeTimeType.Singleton://需要线程安全 双if+lock

{if (this.TypeObjectDictionary.ContainsKey(targetType))

{

para= this.TypeObjectDictionary[targetType];

}else{

para= this.CreateObject(targetType);this.TypeObjectDictionary[targetType] =para;

}

}break;caseLifeTimeType.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");

}

}#endregion

//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数

paraList.Add(para);

}returnActivator.CreateInstance(type, paraList.ToArray());

}//属性注入+方法注入?

}

public classRegisterInfo

{///

///目标类型///

public Type TargetType { get; set; }///

///生命周期///

public LifeTimeType LifeTime { get; set; }

}public enumLifeTimeType

{

Transient,

Singleton,

PerThread

}

IBingleContainer container = newBingleContainer();

container.RegisterType(LifeTimeType.PerThread);

container.RegisterType(LifeTimeType.PerThread);

container.RegisterType(LifeTimeType.Transient);

container.RegisterType(LifeTimeType.Singleton);

container.RegisterType();

container.RegisterType();

container.RegisterType();

IPhone pad1= null;

IPhone pad2= null;

IPhone pad3= null;//pad1 = container.Resolve();

Action act1 = new Action(() =>{

pad1= container.Resolve();

Console.WriteLine($"pad1由线程id={Thread.CurrentThread.ManagedThreadId}");

});var result1 = act1.BeginInvoke(null, null);

Action act2= new Action(() =>{

pad2= container.Resolve();

Console.WriteLine($"pad2由线程id={Thread.CurrentThread.ManagedThreadId}");

});var result2 = act2.BeginInvoke(t =>{

pad3= container.Resolve();

Console.WriteLine($"pad3由线程id={Thread.CurrentThread.ManagedThreadId}");

Console.WriteLine($"object.ReferenceEquals(pad2, pad3)={object.ReferenceEquals(pad2, pad3)}");

},null);

act1.EndInvoke(result1);

act2.EndInvoke(result2);

Console.WriteLine($"object.ReferenceEquals(pad1, pad2)={object.ReferenceEquals(pad1, pad2)}");

容器依赖细节?如果不想依赖细节,又想创建对象,反射+配置文件:

ExeConfigurationFileMap fileMap = newExeConfigurationFileMap();

fileMap.ExeConfigFilename= Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径

Configuration configuration =ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

UnityConfigurationSection section=(UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

IUnityContainer container= newUnityContainer();

section.Configure(container,"testContainer1");//container.AddNewExtension().Configure()//.SetInterceptorFor(new InterfaceInterceptor());

IPhone phone= container.Resolve();

phone.Call();

IPhone android= container.Resolve("Android");

android.Call();

IDBContext context = container.Resolve>();

context.DoNothing();

配置文件:

View Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值