Ioc-Unity整理
来源:互联网 发布:免费顶级域名注册 编辑:程序博客网 时间:2024/06/01 07:26
参考 http://blog.csdn.net/wanzhuan2010/article/details/7763280
http://www.it165.net/pro/html/201407/17685.html
基础概念
IOC(Inversion of Control )——控制反转
即依赖对象不在被依赖模块的类中直接通过new来获取
DI(Dependency Injection)——依赖注入
DI是IoC的一种实现方式,就是将依赖对象的创建和绑定转移到被依赖对象类的外面来实现
依赖注入分为:构造函数注入、属性注入和接口注入
Unit是微软patterns& practices组用C#实现的轻量级、可扩展的依赖注入容器对于小型项目:用代码的方式实现即可
对于中大型项目:使用配置文件比较好
下面开始Unity之旅
用编程方式实现注入
新建一个控制台应用程序,引用Microsoft.Practices.Unity.dll文件;
新建一个鸟类的接口,定义一个鸟叫的方法;
- /// <summary>
- /// 鸟类接口
- /// </summary>
- public interface IBird
- {
- /// <summary>
- /// 讲话
- /// </summary>
- void Say( );
- }
对这个接口进行实现:
- /// <summary>
- /// 燕子
- /// </summary>
- public class Swallow : IBird
- {
- public void Say( )
- {
- Console.WriteLine("燕子在叫...");
- }
- }
在Mian方法中通过Unity实现IOC反转控制;
- static void Main( string[] args )
- {
- //实例化一个控制器
- IUnityContainer unityContainer = new UnityContainer();
- //实现注入
- unityContainer.RegisterType<IBird, Swallow>();
- IBird bird = unityContainer.Resolve<IBird>();
- bird.Say();
- Console.Read();
运行结果:
这个小实例已经实现了简单的IOC控制反转.
当一个接口有多个实现,而且没有用别名区分时,就会选择最后一个注入的实现;
- public class Sparrow : IBird
- {
- public void Say()
- {
- Console.WriteLine("麻雀在叫....");
- }
- }
Main方法代码:
- //实例化一个控制器
- IUnityContainer unityContainer = new UnityContainer();
- //实现注入
- unityContainer.RegisterType<IBird, Swallow>();
- unityContainer.RegisterType<IBird, Sparrow>();
- IBird bird = unityContainer.Resolve<IBird>();
- bird.Say();
- Console.Read();
运行一下,结果:
下边给每个注入都加上别名:
- //实例化一个控制器
- IUnityContainer unityContainer = new UnityContainer();
- //实现注入,用别名区分实现
- unityContainer.RegisterType<IBird, Swallow>("Swallow");
- unityContainer.RegisterType<IBird, Sparrow>("Sparrow");
- IBird swallow = unityContainer.Resolve<IBird>("Swallow");
- IBird sparrow = unityContainer.Resolve<IBird>("Sparrow");
- swallow.Say();
- sparrow.Say();
- Console.Read();
(二) Unity的构造函数注入
新建 一个IBirdHome 接口,并对接口进行实现:
- /// <summary>
- /// 小鸟的家
- /// </summary>
- public interface IBirdHome
- {
- IBird Swallow { get; set; }
- }
- /// <summary>
- /// 小鸟的家
- /// </summary>
- public class BirdHome : IBirdHome
- {
- public IBird Swallow { get; set; }
- public BirdHome(IBird bird)
- {
- this.Swallow = bird;
- }
- }
- //实例化一个控制器
- IUnityContainer unityContainer = new UnityContainer();
- //实现注入
- unityContainer.RegisterType<IBird, Swallow>();
- unityContainer.RegisterType<IBirdHome, BirdHome>();
- IBirdHome birdHome = unityContainer.Resolve<IBirdHome>();
- birdHome.Swallow.Say();
- Console.Read();
我们只是通过Unity得到了一个IBirdHome实现,但并没有对 IBird Swallow { get; set; } 进行实例化,但结果已经运行出来,并没有报错.
原来这些工作Unity已帮我们做了,我们可以偷个懒了.嘿嘿.......
(三)属性注入
把BirdHome类的中构造函数去掉,在属性上加上[Dependency]特性
- /// <summary>
- /// 小鸟的家
- /// </summary>
- public class BirdHome : IBirdHome
- {
- /// <summary>
- /// 属性注入
- /// </summary>
- [Dependency]
- public IBird Swallow { get; set; }
- }
(四) 方法注入
方法注入与构造函数注入相似,但不用写到构造函数里边,而是在初使化方法上加上[InjectionMethod]特性
- /// <summary>
- /// 初始化器注入
- /// </summary>
- /// <param name="bird"></param>
- [InjectionMethod]
- public void Initialize(IBird bird)
- {
- this.Swallow = bird;
- }
<?xml version='1.0' encoding='utf-8'?><configuration> <configSections> <section name='unity' type='Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration'/> </configSections> <unity xmlns=http://schemas.microsoft.com/practices/2010/unity> <!--定义类型别名--> <aliases> <add alias='IClass' type='ConsoleApplication1.UnityDemo.IClass,ConsoleApplication1' /> <add alias='CbClass' type='ConsoleApplication1.UnityDemo.CbClass,ConsoleApplication1' /> <add alias='EcClass' type='ConsoleApplication1.UnityDemo.EcClass,ConsoleApplication1' /> </aliases> <!--容器--> <container name='FirstClass'> <!--映射关系--> <register type='IClass' mapTo='CbClass'></register> <register type='IClass' mapTo='EcClass' name='ec'></register> </container> </unity></configuration>
public static void ContainerConfiguration(){ IUnityContainer container = new UnityContainer();//获取指定名称的配置节 UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection('unity'); container.LoadConfiguration(section, 'FirstClass');//获取特定配置节下已命名的配置节<container name='FirstClass'>下的配置信息 IClass classInfo = container.Resolve<IClass>('ec'); classInfo. ShowInfo();}也可以指定配置文件比如Unity.config
public static void ContainerConfigurationFromFile(string configFile){ //根据文件名获取指定config文件 var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile }; //从config文件中读取配置信息 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); var unitySection = (UnityConfigurationSection)configuration.GetSection('unity'); var container = new UnityContainer().LoadConfiguration(unitySection, 'FirstClass'); IClass classInfo = container.Resolve<IClass>('ec'); classInfo.ShowInfo();}
使用Unity为已存在的对象注册关系
public static void RegisterInstance(){ IClass myClass = new MyClass(); IClass yourClass = new YourClass(); //为myClass实例注册默认实例 container.RegisterInstance<IClass>(myClass); //为yourClass实例注册命名实例,同RegisterType container.RegisterInstance<IClass>('yourInstance', yourClass); container.Resolve<IClass>().ShowInfo(); container.Resolve<IClass>('yourInstance').ShowInfo();}
Unity中生命周期管理
简单介绍一下Unity中内置的两个常用生命周期管理器,其他的生命周期管理器如果需要可以自己上网查看其详细说明(1)TransientLifetimeManager,瞬态生命周期,默认情况下,在使用RegisterType进行对象关系注册时如果没有指定生命周期管理器则默认使用这个生命周期管理器,这个生命周期管理器就如同其名字一样,当使用这种管理器的时候,每次通过Resolve或ResolveAll调用对象的时候都会重新创建一个新的对象。
public static void TransientLifetimeManagerCode(){ //以下2种注册效果是一样的 container.RegisterType<IClass, MyClass>(); container.RegisterType<IClass, MyClass>(new TransientLifetimeManager()); Console.WriteLine('-------TransientLifetimeManager Begin------'); Console.WriteLine('第一次调用RegisterType注册的对象HashCode:' + container.Resolve<IClass>().GetHashCode()); Console.WriteLine('第二次调用RegisterType注册的对象HashCode:' + container.Resolve<IClass>().GetHashCode()); Console.WriteLine('-------TransientLifetimeManager End------');}如果是使用配置的方式,则需要在配置文件中注册关系的时候在<register>配置节下新增<lifetime>既可(如果不新增则默认使用TransientLifetimeManager),如果想使用其他的生命周期管理器,则更改此配置节即可!
<register type='IClass' mapTo='MyClass'> <lifetime type='transient' /></register>
public static void ContainerControlledLifetimeManagerCode(){ IClass myClass = new MyClass(); //以下2种注册效果是一样的 container.RegisterInstance<IClass>('ccl', myClass); container.RegisterInstance<IClass>('ccl', myClass, new ContainerControlledLifetimeManager()); container.RegisterType<IClass, MyClass>(new ContainerControlledLifetimeManager()); Console.WriteLine('-------ContainerControlledLifetimeManager Begin------'); Console.WriteLine('第一次调用RegisterType注册的对象HashCode:' + container.Resolve<IClass>().GetHashCode()); Console.WriteLine('第二次调用RegisterType注册的对象HashCode:' + container.Resolve<IClass>().GetHashCode()); Console.WriteLine('第一次调用RegisterInstance注册的对象HashCode:' + container.Resolve<IClass>('ccl').GetHashCode()); Console.WriteLine('第二次调用RegisterInstance注册的对象HashCode:' + container.Resolve<IClass>('ccl').GetHashCode()); Console.WriteLine('-------ContainerControlledLifetimeManager End------');}
运行之后都会发现实例的哈希码是一样的,说明是单实例的
如果用此生命周期管理器,则要在配置文件中新增的节点如下:
<register type='IClass' mapTo='MyClass' name='ccl'> <lifetime type='singleton' /></register>
public static void HierarchicalLifetimeManagerCode(){ container.RegisterType<IClass, MyClass>(new HierarchicalLifetimeManager()); //创建子容器 var childContainer = container.CreateChildContainer(); childContainer.RegisterType<IClass, MyClass>(new HierarchicalLifetimeManager()); Console.WriteLine("-------ContainerControlledLifetimeManager Begin------"); Console.WriteLine("第一次调用父容器注册的对象HashCode:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("第二次调用父容器注册的对象HashCode:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("第一次调用子容器注册的对象HashCode:" + childContainer.Resolve<IClass>().GetHashCode()); Console.WriteLine("第二次调用子容器注册的对象HashCode:" + childContainer.Resolve<IClass>().GetHashCode()); Console.WriteLine("-------ContainerControlledLifetimeManager End------");}
这边需要提一下的就是,Unity这种分级容器的好处就在于我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。
public interface IPresenter{ } public class MockPresenter : IPresenter{ public IView View { get; set; } public MockPresenter(IView view) { View = view; }} public interface IView{ IPresenter Presenter { get; set; }} public class View : IView{ [Dependency] public IPresenter Presenter { get; set; }}
从这个例子中可以看出,有2个接口IPresenter和IView,还有2个类MockPresenter和View分别实现这2个接口,同时这2个类中都包含了对另外一个类的对象属性,这个就是一个循环引用,而对应的这个生命周期管理就是针对这种情况而新增的,其类似于TransientLifetimeManager,但是其不同在于,如果应用了这种生命周期管理器,则在第一调用的时候会创建一个新的对象,而再次通过循环引用访问到的时候就会返回先前创建的对象实例(单件实例),代码如下:
public static void PerResolveLifetimeManagerCode(){ var container = new UnityContainer() .RegisterType<IPresenter, MockPresenter>() .RegisterType<IView, View>(new PerResolveLifetimeManager()); var view = container.Resolve<IView>(); var tempPresenter = container.Resolve<IPresenter>(); var realPresenter = (MockPresenter)view.Presenter; Console.WriteLine("-------PerResolveLifetimeManager Begin------"); Console.WriteLine("使用了PerResolveLifetimeManager的对象 Begin"); Console.WriteLine("通过Resolve方法获取的View对象:" + view.GetHashCode()); Console.WriteLine("View对象中的Presenter对象所包含的View对象:" + realPresenter.View.GetHashCode()); Console.WriteLine("使用了PerResolveLifetimeManager的对象 End"); Console.WriteLine(""); Console.WriteLine("未使用PerResolveLifetimeManager的对象 Begin"); Console.WriteLine("View对象中的Presenter对象:" + realPresenter.GetHashCode()); Console.WriteLine("通过Resolve方法获取的View对象:" + tempPresenter.GetHashCode()); Console.WriteLine("未使用PerResolveLifetimeManager的对象 End"); Console.WriteLine("-------PerResolveLifetimeManager Begin------");}
从代码中可以看出,在注册对象的时候,仅对IView和View应用了PerResolveLifetimeManager,所以第二次访问View对象会返回同一实例。
具体配置文件如下,有关构造函数注入和属性注入的内容在下一篇文章中进行介绍:
<alias alias="IPresenter" type="UnityStudyConsole.IPresenter, UnityStudyConsole" /><alias alias="IView" type="UnityStudyConsole.IView, UnityStudyConsole" /><alias alias="MockPresenter" type="UnityStudyConsole.MockPresenter, UnityStudyConsole" /><alias alias="View" type="UnityStudyConsole.View, UnityStudyConsole" /><container name="Second"> <register type="IPresenter" mapTo="MockPresenter"> <constructor> <param name ="view" type="IView"> </param> </constructor> </register> <register type="IView" mapTo="View" > <lifetime type="perresolve"/> <property name="Presenter" dependencyType="IPresenter"></property> </register></container>
(5)PerThreadLifetimeManager,每线程生命周期管理器,就是保证每个线程返回同一实例,具体代码如下:
public static void PerThreadLifetimeManagerCode(){ container.RegisterType<IClass, MyClass>(new PerThreadLifetimeManager()); var thread = new Thread(new ParameterizedThreadStart(Thread1)); Console.WriteLine("-------PerResolveLifetimeManager Begin------"); Console.WriteLine("默认线程 Begin"); Console.WriteLine("第一调用:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("第二调用:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("默认线程 End"); thread.Start(container);} public static void Thread1(object obj){ var tmpContainer = obj as UnityContainer; Console.WriteLine("新建线程 Begin"); Console.WriteLine("第一调用:" + tmpContainer.Resolve<IClass>().GetHashCode()); Console.WriteLine("第二调用:" + tmpContainer.Resolve<IClass>().GetHashCode()); Console.WriteLine("新建线程 End");
Console.WriteLine("-------PerResolveLifetimeManager End------"); }
有关配置相关的代码与前面的生命周期管理器差不多,这边就不贴代码了,请看示例代码。
具体效果图如下:
(6)ExternallyControlledLifetimeManager,外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁掉。
在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象,示例代码如下
public static void ExternallyControlledLifetimeManagerCode(){ container.RegisterType<IClass, MyClass>(new ExternallyControlledLifetimeManager()); var myClass1 = container.Resolve<IClass>(); var myClass2 = container.Resolve<IClass>(); Console.WriteLine("-------ExternallyControlledLifetimeManager Begin------"); Console.WriteLine("第一次调用:" + myClass1.GetHashCode()); Console.WriteLine("第二次调用:" + myClass2.GetHashCode()); myClass1 = myClass2 = null; GC.Collect(); Console.WriteLine("****GC回收过后****"); Console.WriteLine("第一次调用:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("第二次调用:" + container.Resolve<IClass>().GetHashCode()); Console.WriteLine("-------ExternallyControlledLifetimeManager End------");}
有关配置相关的代码与前面的生命周期管理器差不多,这边就不贴代码了,请看示例代码。
效果图如下:
以上就是本文的全部内容了,主要介绍了使用UnityContainer来注册对象之间的关系、注册已存在的对象之间的关系和Unity内置的生命周期管理器。
- Ioc-Unity整理
- IOC Unity
- .net ioc框架 unity
- IOC容器Unity 使用
- Microsoft Unity--IOC/DI
- Spring IoC知识点整理
- IoC知识整理(二)
- IoC知识整理(一)
- IOC/DI 理解整理
- [IoC容器Unity]第一回:Unity预览
- IOC容器——Unity
- IOC unity的配置文件注意事项
- Spring IOC/DI 简单整理
- Spring 知识点整理 之 IOC
- Unity自动更新、AssetBundle整理
- [Unity]面试题整理
- Unity NetworkManager整理160616
- Unity知识点整理
- .NET用NCO连接SAP 从RFC查询数据 代码配置连接SAP的信息
- gdb 使用笔记
- Stl各容器对比
- BP Neural Networks初步理解
- spring+springMVC,声明式事务失效,原因以及解决办法
- Ioc-Unity整理
- [LeetCode OJ]ZigZag Conversion && Valid Sudoku && String to Integer (atoi)
- [BZOJ 1043][HAOI 2008]下落的圆盘(计算几何)
- ubuntu下ftp常识用法
- 示例解读Java的跨平台原理
- Apache_Maven基本配置和使用
- Swift语法基础:9 - Swift的字面量, 类型转换, 类型别名
- Java的数据库事务处理
- 安装版Tomcat的使用