微软企业库Unity学习笔记
本文主要介绍:
关于Unity container配置,注册映射关系、类型,单实例、已存在对象和指出一些container的基本配置,这只是我关于Unity的学习心得和笔记,希望能够大家多交流相互学习到更多知识,谢谢大家的支持。
我们可以通过以下两种方法给Unity container中创建映射:
- RegisterType:这个方法可以往container中注册一种类型或映射关系,当我们需要调用该类型的实例时,container会自动实例化该类型的对象,无需通过new someName方法实例化对象(例如:使用Resolve或ResolveAll方法获取注册类型的实例),当没有指定实例化对象的生命周期,将使用默认的TransientLifetimeManager(每次调用Resolve或ResolveAll方法时都会实例化一个新的对象)。
- RegisterInstance:这个方法是往container中注册一个已存在实例,通过Resolve或ResolveAll方法获取该类型的实例,默认使用ContainerControlledLifetimeManager管理对象生命周期,而且container中会保持对象的引用(简而言之每次调用Resolve或ResolveAll方法都会调用同一个对象的引用)。
1.1 注册一个接口或类的映射到具体类型:
使用Register方法可以往容器中注册一种类型或映射关系
- l 往容器中注册一种类型RegisterType<Type>
- l 往容器中注册一种映射关系RegisterType< RegisteredType, TargetType >
调用RegisterType<RegisteredType, TargetType>()方法可以往容器中注册一种映射关系,RegisteredType是一个接口或类,而TargetType必需实现该接口或继承该类。
1.2 注册一个单例类或单例类型实例:
涉及到对象的生命周期(Lifetime Managers):
- l 默认的情况下使用TransientLifetimeManager管理对象的生命周期,以下两种方法效果一样:
container.RegisterType<IMyService, CustomerService>(new TransientLifetimeManager());
- l 使用ContainerControlledLifetimeManager创建单例实例
- l 使用ExternallyControlledLifetimeManager只可以保持对象的弱引用
关于强引用和弱引用:
强引用:当一个根指向一个对象时,该对象不可能被执行垃圾收集,因为程序代码还在访问该对象。
弱引用:允许垃圾收集器收集对象,同时允许应用程序访问该对象,结果是执行哪个要取决于时间。
- l 使用PerThreadLifetimeManager在同一个线程返回同一个对象实例,不同线程对象实例不相同
在使用RegisterType注册类型或映射,如果对对象生命周期进行,将使用默认的TransientLifetimeManager,它不会在container中保存对象的引用,简而言之每当调用Resolve或ResolveAll方法时都会实例化一个新的对象。当我们想在container中保存对象的引用的时我们可以使用ContainerControlledLifetimeManager管理对象的生命周期,简而言之每次调用Resolve或ResolveAll方法都会调用同一个对象的引用。
1.3 注册一个存在对象作为单件实例:
注册一个存在的对象我们使用的是RegisterInstance,它默认使用ContainerControlledLifetimeManager管理对象的生命周期,回顾以下
RegisterType和RegisterInstance区别:
Method |
Default Lifetime Managers |
Same Lifetime Managers |
RegisterType |
TransientLifetimeManager |
ContainerControlledLifetimeManager |
RegisterInstance |
ContainerControlledLifetimeManager |
ContainerControlledLifetimeManager |
当RegisterType和RegisterInstance都使用ContainerControlledLifetimeManager时的区别:
MSDN:If you used the RegisterType method to register a type, Unity creates a new instance of the registered type during the first call to the Resolve or ResolveAll method or when the dependency mechanism injects instances into other classes. Subsequent requests return the same instance.
If you used the RegisterInstance method to register an existing object, Unity returns this instance every time you call the Resolve or ResolveAll method or when the dependency mechanism injects instances into other classes.
翻译:如果使用RegisterType方法注册一种类型,当第一次调用Resolve 或ResolveAll 方法或依赖机制注入一个实例到其他类时,Unity会实例化该注册类型,之后的调用都返回相同实例。
如果使用RegisterInstance方法注册一个存在对象,当我们调用Resolve和ResolveAll方法或赖机制注入一个实例到其他类时,Unity每次都返回该对象实例。
1.4 使用container的fluent interface属性:
这意味着你可以在一条语句中使用方法链
- IUnityContainer myContainer =new UnityContainer()
- .RegisterType<IMyService, DataService>()
- .RegisterType<IMyUtilities, DataConversions>()
- .RegisterInstance<IMyService>(myEmailService);
由于IUnityContainer 接口实现了IDispose接口,所有我们可以使用Using控制container资源释放
- ////IUnityContainer实现接口IDisposable,所以可以使用
- ////using有效释放对象占用的系统资源。
- using (IUnityContainer container =new UnityContainer())
- {
- ////实现
- }
接下来介绍一下依赖注入的方式:
- 构造函数注入
- 属性注入
- 方法注入
一、 构造函数注入
我们将介绍单构造函数和多构造函数注入
1) 单构造函数使用自动注入
- 单构造函数自动注入,这里我们使用一个简单的例子具体类MyObject依赖于具体类MyDependentClass。
- ////具体类型的依赖关系
- publicclass MyOjbect
- {
- privatestring description;
- publicstring Description
- {
- get { return description; }
- set { description = value; }
- }
- public MyOjbect(MyDependentClass myDependent)
- {
- this.Description = myDependent.Description;
- }
- }
- ////注入依赖
- MyOjbect objlist = container.Resolve<MyOjbect>();
- 当然除了具体类型我们还可以使用接口或者基类类型作为参数注入依赖,这里我们定义一个接口和一个抽象类。
- //// MyServiceBase是一个抽象类,然后objIMyService继承于该抽象类
- //// IMyService是一个接口,objMyService实现该接口
- publicclass MyOjbect
- {
- privatestring description;
- publicstring Description
- {
- get { return description; }
- set { description = value; }
- }
- public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
- {
- ////TODO:
- }
- }
- ////注册抽象类和接口的映射关系
- container.RegisterType<IMyService, MyServiceDependent>();
- container.RegisterType<MyServiceBase, DataService>();
- MyOjbect objlist = container.Resolve<MyOjbect>();
2) 多重载构造函数通过属性指定注入构造函数
通过InjectionConstructor属性指定要注入构造函数,和单构造函数功能一样,但要注意一点是当有多重载构造函数,如果我们没有使用属性指定注入构造函数,Unity会根据构造函数参数最多的进行依赖注入,如果不存在唯一最多参数的构造函数(例如:有两个或者两个以上构造函数具有最多参数时候),Unity会抛出异常。
- publicclass MyOjbect
- {
- privatestring description;
- publicstring Description
- {
- get { return description; }
- set { description = value; }
- }
- public MyOjbect(MyServiceBase objIMyService)
- {
- ////
- }
- [InjectionConstructor]
- public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
- {
- ////
- }
- }
通过前面的介绍我们初步明白了Unity的作用就是给我们一个更方便实现类与类的解耦,假设在一般情况一个类依赖于其他类的时候,我们必须实例化该依赖类,然后把实例传递给我们要调用类,但有了Unity它帮我们实例了这些。OK接下来讲一个具体例子。
- ///<summary>
- /// 父母类
- ///</summary>
- publicclass Parent
- {
- privatereadonly ChildA _classA;
- privatereadonly ChildB _classB;
- public Parent() { }
- //指定依赖注入构造函数
- [InjectionConstructor]
- public Parent(ChildA chA, ChildB chB)
- {
- this._classA = chA;
- this._classB = chB;
- }
- publicoverridestring ToString()
- {
- // 年长的父母依赖与孩子。
- returnstring.Format("The elder depend on {0} and {1}.", this._classA.ToString(), this._classB.ToString());
- }
- }
- ///<summary>
- /// 孩子类
- ///</summary>
- publicclass ChildA : Parent
- {
- publicoverridestring ToString()
- {
- return"ChildA";
- }
- }
- ///<summary>
- /// 孩子类
- ///</summary>
- publicclass ChildB : Parent
- {
- publicoverridestring ToString()
- {
- return"ChildB";
- }
- }
- class Program
- {
- staticvoid Main(string[] args)
- {
- using (IUnityContainer container =new UnityContainer())
- {
- Parent objParent = container.Resolve<Parent>();
- Console.WriteLine(objParent.ToString());
- Console.ReadKey();
- }
- }
- }
接下通过一个简单的配置文件实例例子进一步说明,Unity是如何实现类与类之间的解耦的。
首先我们先定义一个Foo类,它依赖于一个接口ILogger,它有两个实现分别是LoggerA和LoggerB,然后我们的Foo类要调用LoggerA。在一般情况下我们可以实例化一个LoggerA的实例,然后传递给Foo就OK了,这就是hard code给我们带来了一个紧的耦合,如果要我们修改成调用LoggerB,那么我们可以再实例化一个LoggerB对象,眼前看来是可以这样实现,但如果我们工程很大,这种做法是十分危险,当我们使用配置文件可以简单实现,来讲讲简单实现。
- staticvoid Main(string[] args)
- {
- using (IUnityContainer container =new UnityContainer())
- {
- ////Parent objParent = container.Resolve<Parent>();
- ////Console.WriteLine(objParent.ToString());
- ////Console.ReadKey();
- //获取指定名称的配置节
- UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
- //获取container名称为CfgClass下的配置
- section.Containers["CfgClass"].Configure(container);
- Foo myFoo = container.Resolve<Foo>();
- Console.WriteLine(myFoo.ToString());
- Console.ReadKey();
- }
- }
App.config中的配置如下:
- <configuration>
- <configSections>
- <!-- 每次都必须定义的开头 -->
- <section name ="unity" type ="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
- Microsoft.Practices.Unity.Configuration"/>
- </configSections>
- <!-- 使用unity的xsd -->
- <!--<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">-->
- <unity>
- <!-- 声明一种是用类型 -->
- <typeAliases>
- <typeAlias alias ="ILogger" type ="MSEnterpriseUnitity.ILogger, MSEnterpriseUnitity"/>
- </typeAliases>
- <containers>
- <container name="CfgClass">
- <!-- 设定该类型的映射关系 -->
- <types>
- <type type ="ILogger" mapTo="MSEnterpriseUnitity.LoggerA, MSEnterpriseUnitity"/>
- </types>
- </container>
- </containers>
- </unity>
- </configuration>
二、方法注入
当一个类的方法依赖于其他类的时候(例如构造函数参数依赖与其他类),在一般情况下通过实例化该被依赖类对象,然后将参数传递给我们依赖类的方法,如果使用方法注入可以避免实例化被依赖类对象,这里就仅仅需要在依赖方法中设置一个属性InjectionMethod就OK了。
2.1方法依赖于具体类
首先我们定义两个类MyTargetOjbect和OtherObject,然后定义在MyTargetOjbect中定义一个方法Initialize(OtherObject dep),该方法的参数依赖于OtherObject类。
- ///<summary>
- /// 依赖类包含一个Description和OutPut方法。
- ///</summary>
- publicclass OtherObject
- {
- privatestring _description;
- publicstring Description
- {
- get { return _description; }
- set { _description = value; }
- }
- publicvoid OutPut()
- {
- Console.WriteLine(this.Description);
- }
- }
- ///<summary>
- /// 目标类的方法Initialize参数依赖于OtherObject类。
- ///</summary>
- publicclass MyTargetOjbect
- {
- public OtherObject dependentObject;
- [InjectionMethod]
- publicvoid Initialize(OtherObject dep)
- {
- this.dependentObject = dep;
- }
- }
- using (IUnityContainer container =new UnityContainer())
- {
- MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
- myTargetObject.dependentObject.Description ="Injection successful.";
- myTargetObject.dependentObject.OutPut();
- }
2.2 方法依赖于接口或者基类
定义一个抽象类MyBaseClass,然后MyInheritBase继承该抽象类,定义一个接口IMyInterface然后ImplementInterface实现该接口。
- ///<summary>
- /// 接口包含一个属性和一个方法
- ///</summary>
- publicinterface IMyInterface
- {
- string Description
- {
- get;
- set;
- }
- void OutPut();
- }
- ///<summary>
- /// 实现IMyInterface的属性和方法
- ///</summary>
- publicclass ImplementInterface : IMyInterface
- {
- privatestring _description;
- #region IMyInterface 成员
- publicstring Description
- {
- get
- {
- return _description;
- }
- set
- {
- _description = value;
- }
- }
- publicvoid OutPut()
- {
- Console.WriteLine(this.Description);
- }
- #endregion
- }
- ///<summary>
- /// 一个抽象类包含一个属性和一个方法
- ///</summary>
- publicabstractclass MyBaseClass
- {
- privatestring _description;
- publicvirtualstring Description
- {
- get { return _description; }
- set { _description = value; }
- }
- publicabstractvoid OutPut();
- }
- ///<summary>
- /// 实现抽象类的抽象方法
- ///</summary>
- publicclass MyInheritBase : MyBaseClass
- {
- publicoverridevoid OutPut()
- {
- Console.WriteLine(this.Description);
- }
- }
- ///<summary>
- /// 目标类的方法Initialize参数依赖于OtherObject类。
- ///</summary>
- publicclass MyTargetOjbect
- {
- public IMyInterface myInterface;
- public MyBaseClass myBase;
- [InjectionMethod]
- publicvoid Initialize(IMyInterface myInterface, MyBaseClass myBase)
- {
- this.myInterface = myInterface;
- this.myBase = myBase;
- }
- }
- ////设置抽象类和接口的映射关系
- container.RegisterType<MyBaseClass, MyInheritBase>();
- container.RegisterType<IMyInterface, ImplementInterface>();
- MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
- myTargetObject.myInterface.Description ="Injection Successful.";
- myTargetObject.myInterface.OutPut();
- myTargetObject.myBase.Description ="Injection Successful.";
- myTargetObject.myBase.OutPut();
三、属性注入
当一个类的属性依赖于其他类,一般情况初始化该属性需要实例化该类型对象,然而我们可以使用Dependency属性,指定属性注入无限手动实例化类型对象。
3.1 具体类型属性
- publicclass MyObject
- {
- private SomeOtherObject _dependentObject;
- [Dependency]
- public SomeOtherObject DependentObject
- {
- get { return _dependentObject; }
- set { _dependentObject = value; }
- }
- }
- IUnityContainer uContainer =new UnityContainer();
- MyObject myInstance = uContainer.Resolve<MyObject>();
- // now access the property containing the dependency
- SomeOtherObject depObj = myInstance.DependentObject;
3.2抽象类或接口属性
- publicclass MyObject
- {
- private IMyInterface _interfaceObj;
- private MyBaseClass _baseObj;
- [Dependency]
- public IMyInterface InterfaceObject
- {
- get { return _interfaceObj; }
- set { _interfaceObj = value; }
- }
- [Dependency]
- public MyBaseClass BaseObject
- {
- get { return _baseObj; }
- set { _baseObj = value; }
- }
- }
- IUnityContainer uContainer =new UnityContainer()
- .RegisterType<IMyInterface, FirstObject>()
- .RegisterType<MyBaseClass, SecondObject>();
- MyObject myInstance = uContainer.Resolve<MyObject>();
- // now access the properties containing the dependencies
- IMyInterface depObjA = myInstance.InterfaceObject;
- MyBaseClass depObjB = myInstance.BaseObject;
3.3 给属性注入命名
给属性命名只需在Dependency(“name”)定义一个名字就OK了。
- publicclass MyTargetOjbect
- {
- public IMyInterface myInterface;
- public MyBaseClass myBase;
- private IMyInterface _MyProperty1, _MyProperty2;
- //命名属性注入
- [Dependency("Property2")]
- public IMyInterface MyProperty2
- {
- get { return _MyProperty2; }
- set { _MyProperty2 = value; }
- }
- //命名属性注入
- [Dependency("Property1")]
- public IMyInterface MyProperty1
- {
- get { return _MyProperty1; }
- set { _MyProperty1 = value; }
- }
- }
- //调用Property1属性注入
- container.RegisterType<IMyInterface, ImplementInterface>("Property1");
- //调用Property2属性注入
- container.RegisterType<IMyInterface, ImplementInterface2>("Property2");
- MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
- IMyInterface myProperty1 = myTargetObject.MyProperty1;
- IMyInterface myProperty2 = myTargetObject.MyProperty2;
3.4 构造函数参数的属性注入
构造函数参数依赖于其他类时候,我们可以考虑使用构造函数注入或者属性注入
- publicclass Foo
- {
- private ILogger _iLogger;
- public Foo([Dependency] ILogger iLogger)
- {
- this._iLogger = iLogger;
- }
- publicoverridestring ToString()
- {
- returnstring.Format("Foo depends on {0}.", this._iLogger.ToString());
- }
- }
- [出处]: http://www.cnblogs.com/rush/
微软企业库Unity学习笔记的更多相关文章
- 微软企业库Unity依赖注入
Unity Application Block 1.0系列(4): 方法调用注入(Method Call Injection ) http://www.cnblogs.com/inrie/archiv ...
- [EntLib]微软企业库5.0 学习之路——第一步、基本入门
话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...
- 使用微软企业库5.0提供的unity配置解藕系统demo(源码)
最近公司集50多号开发人员的人力围绕一个系统做开发,框架是免不了要统一的,公司提供的架构,利于分工合作,便于维护,扩展,升级,其中使用了到微软的企业库来解藕系统,只是因为框架封装,于是在网上学习了一个 ...
- 微软企业库5.0 学习之路——第八步、使用Configuration Setting模块等多种方式分类管理企业库配置信息
在介绍完企业库几个常用模块后,我今天要对企业库的配置文件进行处理,缘由是我打开web.config想进行一些配置的时候发现web.config已经变的异常的臃肿(大量的企业库配置信息充斥其中),所以决 ...
- 微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇
在上一篇文章中, 我介绍了企业库Cryptographer模块的一些重要类,同时介绍了企业库Cryptographer模块为我们提供的扩展接口,今天我就要根据这些 接口来进行扩展开发,实现2个加密解密 ...
- 微软企业库5.0 学习之路——第六步、使用Validation模块进行服务器端数据验证
前端时间花了1个多星期的时间写了使用jQuery.Validate进行客户端验证,但是那仅仅是客户端的验证,在开发项目的过程中,客户端的信息永远是不可信的,所以我们还需要在服务器端进行服务器端的验证已 ...
- 微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——下篇
一.独立验证器 我上篇中我将AndCompositeValidator和OrCompositeValidator归为独立验证器,这2个验证器主要是为了第一类验证服务,可以进行多种验证组合在一起进行复杂 ...
- 微软企业库5.0 学习之路——第四步、使用缓存提高网站的性能(EntLib Caching)
首先先补习下企业库的Caching Application Block的相关知识: 1.四大缓存方式,在Caching Application Block中,主要提供以下四种保存缓存数据的途径,分别是 ...
- 微软企业库5.0 学习之路——第二步、使用VS2010+Data Access模块建立多数据库项目
现在我就开始进入学习之路的第二步——Data Access模块,这个模块是企业库中被使用频率最高的模块,它很好的封装了数据库操作应用,为我们进行多数据库系统开发提供了便利,只需更改配置文件就 可以很快 ...
随机推荐
- Phoenix的安装使用与SQL查询HBase
一. Phoenix的简介 1. 什么是phoenix 现有hbase的查询工具有很多如:Hive,Tez,Impala,Shark/Spark,Phoenix等.今天主要说Phoenix.phoen ...
- bzoj 4552
4552 思路: 二分线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define ...
- ASP.NET MVC之Ajax如影随行
一.Ajax的前世今生 我一直觉得google是一家牛逼的公司,为什么这样说呢?<舌尖上的中国>大家都看了,那些美食估计你是百看不厌,但是里边我觉得其实也有这样的一个哲学:关于食材,对于种 ...
- 【LOJ】#2542. 「PKUWC2018」随机游走
题解 虽然我知道minmax容斥,但是--神仙能想到把这个dp转化成一个一次函数啊= = 我们相当于求给定的\(S\)集合里最后一个被访问到的点的时间,对于这样的max的问题,我们可以用容斥把它转化成 ...
- .NET Runtime version 2.0.50727.xxx 执行引擎错误。 (Fatal Execution Engine Error)
如题问题困扰本人良久. 尝试VS2005.VS2008.VS2010均出现过次问题. 主要现象: 1. Window设计器会崩溃,直接挂掉.(当逐条注释掉一些静态构造函数内的代码是情况好转) 2. 发 ...
- Ionic Js六:切换开关操作
以下实例中,通过切换不同开关 checked 显示不同的值,true 为打开,false 为关闭. HTML 代码 <ion-header-bar class="bar-positiv ...
- 通过GeneXus如何快速构建微服务架构
概览 “微服务”是一个非常广泛的话题,在过去几年里,市面上存在着各种不同的定义. 虽然对这种架构方式没有一个非常精确的定义,但仍然有一些概念具有代表性. 微服务有着许多围绕业务能力.自动化部署.终端智 ...
- [leetcode DP]53. Maximum Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest ...
- 再谈应用环境下的TIME_WAIT和CLOSE_WAIT
昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: http://blog.csdn.net/shootyou/article/details/6615051 里头的分析过程有 ...
- javascript面向对象系列第五篇
<style> .test{height: 50px;width: 50px;background-color: pink;position:absolute;} #test2{left: ...