Unity模块的亮点
Unity模块包括了下面的特点
- 提供了一个创建对象,以及依赖的对象的方法
- 提供的RegisterType方法用来在容器中注册类型和映射,Resolve方法可以返回任何依赖对象的实例。
- 提供控制反转IOC功能,通过预先配置注入类的对象来实现。你可以在构造函数中指明一个类或者接口(构造函数注入),或者是使用attribute的属性注入,和方法调用注入。
- 支持容器继承,容器可以有子容器,支持对象从子容器传递到父容器中。
- 可以从标准的配置文件中读取信息,例如xml文件
- 对类的定义没有任何要求。在类上不需要添加attribute(除非使用属性注入或者是方法调用注入),在类声明中没有任何限制。
- 支持自定义容器,例如,你可以在方法中实现额外的对象构造,和容器功能,例如容器的缓存功能。
什么时候使用Unity模块
依赖注入提供了简化代码的机会,抽象对象之间的依赖,自动产生依赖对象的实例。但是,处理的过程对性能上有一点小的损失,而且可能会使得只需要简单依赖的地方变得复杂。
通常来说,在下列情况你应该使用Unity模块:
- 对象和类与其他对象和类有依赖关系。
- 你的依赖关系是复杂的,或者是需要抽象。
- 你需要构造函数、方法、或者是属性注入的功能。
- 你需要管理对象实例的生命周期。
- 你需要在运行的时候可以配置和改变依赖关系。
- 你需要在web应用中缓存或者是持久化依赖关系。
在下面的情况,你不应该使用Unity模块
- 你的对象和类与其他的对象和类没有依赖关系。
- 你的依赖关系很简单,不需要抽象。
在开发的过程中使用Unity模块
这个主题描述如何在应用开发中使用Unity模块。如何创建对象实例。
使用Unity模块的系统需要
最小需要如下:
- Microsoft Windows XP Professional,Windows Server 2003,Windows Server 2008 or Windows Vista operating System。
- Microsoft .NET Framework 2.0,3.0 or 3.5。
- Microsoft Visual Studio 2005 or 2008 development system。
配置Unity模块
Unity模块可以从xml配置文件中读取配置信息。默认情况下,就是应用中的app.config或者是web.config文件。你也可以从其他xml文件,或者是其他来源加载配置信息。
在运行的时候配置容器
1.格式化Unity配置文件
下面的xml格式就是Unity的配置格式。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
<
configuration
>
<
configSections
>
<
section
name
="unity"
type
="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"
/>
</
configSections
>
<
unity
>
... ...
</
unity
>
... ...
</
configuration
>
下面是一个比较完整的配置文件
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
configSections
>
<
section
name
="unity"
type
="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft patterns & practices – Unity Application Block 1.2 – October 2008 27
Microsoft.Practices.Unity.Configuration, =1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
/>
</
configSections
>
<
unity
>
<
typeAliases
>
<!--
Lifetime manager types
-->
<
typeAlias
alias
="singleton"
type
="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity"
/>
<
typeAlias
alias
="perThread"
type
="Microsoft.Practices.Unity.PerThreadLifetimeManager, Microsoft.Practices.Unity"
/>
<
typeAlias
alias
="external"
type
="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity"
/>
<!--
User-defined type aliases
-->
<
typeAlias
alias
="IMyInterface"
type
="MyApplication.MyTypes.MyInterface, MyApplication.MyTypes"
/>
<
typeAlias
alias
="MyRealObject"
type
="MyApplication.MyTypes.MyRealObject, MyApplication.MyTypes"
/>
<
typeAlias
alias
="IMyService"
type
="MyApplication.MyTypes.MyService, MyApplication.MyTypes"
/>
<
typeAlias
alias
="MyDataService"
type
="MyApplication.MyTypes.MyDataService, MyApplication.MyTypes"
/>
<
typeAlias
alias
="MyCustomLifetime"
type
="MyApplication.MyLifetimeManager, MyApplication.MyTypes"
/>
</
typeAliases
>
<
containers
>
<
container
name
="containerOne"
>
<
types
>
<!--
Type mapping with no lifetime – defaults to "transient"
-->
<
type
type
="Custom.MyBaseClass"
mapTo
="Custom.MyConcreteClass"
/>
<!--
Type mapping using aliases defined above
-->
<
type
type
="IMyInterface"
mapTo
="MyRealObject"
name
="MyMapping"
/>
<!--
Lifetime managers specified using the type aliases
-->
<
type
type
="Custom.MyBaseClass"
mapTo
="Custom.MyConcreteClass"
>
<
lifetime
type
="singleton"
/>
</
type
>
28 Microsoft patterns & practices – Unity Application Block 1.2 – October 2008
<
type
type
="IMyInterface"
mapTo
="MyRealObject"
name
="RealObject"
>
<
lifetime
type
="perThread"
/>
</
type
>
<
type
type
="IMyInterface"
mapTo
="MyRealObject"
name
="RealObject"
>
<
lifetime
type
="external"
/>
</
type
>
<!--
Lifetime manager specified using the full type name
-->
<!--
Any initialization data specified for the lifetime manager
-->
<!--
will be converted using the default type converter
-->
<
type
type
="Custom.MyBaseClass"
mapTo
="Custom.MyConcreteClass"
>
<
lifetime
value
="sessionKey"
type
="MyApplication.MyTypes.MyLifetimeManager, MyApplication.MyTypes"
/>
</
type
>
<!--
Lifetime manager initialization using a custom TypeConverter
-->
<
type
type
="IMyInterface"
mapTo
="MyRealObject"
name
="CustomSession"
>
<
lifetime
type
="MyCustomLifetime"
value
="ReverseKey"
typeConverter
="MyApplication.MyTypes.MyTypeConverter, MyApplication.MyTypes"
/>
</
type
>
<!--
Object with injection parameters defined in configuration
-->
<!--
Type mapping using aliases defined above
-->
<
type
type
="IMyService"
mapTo
="MyDataService"
name
="DataService"
>
<
typeConfig
extensionType
="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"
>
<
constructor
>
<
param
name
="connectionString"
parameterType
="string"
>
<
value
value
="AdventureWorks"
/>
</
param
>
<
param
name
="logger"
parameterType
="ILogger"
>
<
dependency
/>
</
param
>
</
constructor
>
<
property
name
="Logger"
propertyType
="ILogger"
/>
<
method
name
="Initialize"
>
<
param
name
="connectionString"
parameterType
="string"
>
<
value
value
="contoso"
/>
</
param
>
<
param
name
="dataService"
parameterType
="IMyService"
>
<
dependency
/>
</
param
>
</
method
>
</
typeConfig
>
</
type
>
Microsoft patterns & practices – Unity Application Block 1.2 – October 2008 29
</
types
>
<
instances
>
<
add
name
="MyInstance1"
type
="System.String"
value
="Some value"
/>
<
add
name
="MyInstance2"
type
="System.DateTime"
value
="2008-02-05T17:50:00"
/>
</
instances
>
<
extensions
>
<
add
type
="MyApp.MyExtensions.SpecialOne"
/>
</
extensions
>
<
extensionConfig
>
<
add
name
="MyExtensionConfigHandler"
type
="MyApp.MyExtensions.SpecialOne.ConfigHandler"
/>
</
extensionConfig
>
</
container
>
<!--
... more containers here ...
-->
</
containers
>
</
unity
>
</
configuration
>
将配置信息加载到容器中
Unity不会自动读取配置信息来创建和准备好一个容器。你需要在应用中用代码来初始化容器,你也可以用代码注册类型,类型映射,任何从文件中读取的扩展信息都可以用代码来创建。
如果配置定义了一个未命名的容器,这个没有名字的容器就是默认的容器。你也可以给容器命名。你可以将每一个容器的配置信息加载到容器中,
下面的代码就是初始化一个新的容器,然后加载配置文件中配置的类型,映射,和扩展定义。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
IUnityContainer container
=
new
UnityContainer();
UnityConfigurationSection section
=
(UnityConfigurationSection)ConfigurationManager.GetSection(
"
unity
"
);
section.Containers.Default.Configure(container);
加载容器的时候,你也可以使用容器的名称进行加载。下面的代码就是加载了一个名为containerOne的容器。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
IUnityContainer container
=
new
UnityContainer();
UnityConfigurationSection section
=
(UnityConfigurationSection)ConfigurationManager.GetSection(
"
unity
"
);
section.Containers[
"
containerOne
"
].Configure(container);
创建一个在配置文件中定义的有继承关系嵌套的容器,你可以用CreateChildContainer方法加载每一个适当的容器信息。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
IUnityContainer parentContainer
=
new
UnityContainer();
IUnityContainer childContainer
=
parentContainer.CreateChildContainer();
UnityConfigurationSection section
=
(UnityConfigurationSection)ConfigurationManager.GetSection(
"
unity
"
);
section.Containers[
"
containerOne
"
].GetConfigCommand().Configure(parentContainer);
section.Containers[
"
nestedChildContainer
"
].Configure(childContainer);
你不能在配置文件中嵌套容器,在containers节中的所有container元素都是同一个级别的元素。容器嵌套是通过代码来创建,并且加载适当的容器。
使用可替代的配置源
如果有需要的话,你可以使用任何xml文件或者是其他源作为配置信息。例如,你可以用System.Configuration.Configuration类获取任何xml文件的配置信息,下面的代码中就是这样用的。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
ExeConfigurationFileMap map
=
new
ExeConfigurationFileMap();
map.ExeConfigFilename
=
"
MyConfig.config
"
;
System.Configuration.Configuration config
=
ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
UnityConfigurationSection section
=
(UnityConfigurationSection)config.GetSection(
"
unity
"
);
IUnityContainer container
=
new
UnityContainer();
section.Containers[
"
myContainer
"
].Configure(container);
配置支持数组
Unity支持设计时数组参数,和运行是数组参数。
在设计的时候配置支持数组参数
在配置文件中使用array元素作为list的代表。array元素描述了一个包含注册实例和类型映射的数组。array可以嵌套使用,包含下面三个子元素:
- array
- dependency
- value
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
<
typeAlias
alias
="ILoggerArray"
type
="Microsoft.Practices.Unity.TestSupport.ILogger[], TestSupport.Unity"
/>
-
<
typeAlias
alias
="ArrayConstructor"
type
="Microsoft.Practices.Unity.TestSupport.ObjectArrayConstructorDependency, Tests.Unity.Configuration"
/>
</
typeAliases
>
-
<
containers
>
<
container
name
="emptyArray"
>
<
types
>
<
type
type
="ArrayConstructor"
>
<
typeConfig
>
<
constructor
>
<
param
name
="loggers"
parameterType
="ILoggerArray"
>
<
array
/>
</
param
>
</
constructor
>
</
typeConfig
>
</
type
>
Microsoft patterns & practices – Unity Application Block 1.2 – October 2008 33
</
types
>
</
container
>
下面的配置文件使用dependency子元素描述了获取指定类型的实例
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
<
typeAliases
>
<
typeAlias
alias
="ILogger"
type
="Microsoft.Practices.Unity.TestSupport.ILogger, TestSupport.Unity"
/ <typeAliases
>
<
container
name
="populatedArrayWithValues"
>
<
types
>
<
type
type
="ILogger"
mapTo
="MockLogger"
name
="logger1"
>
<
lifetime
type
="singleton"
/>
</
type
>
<
type
type
="ILogger"
mapTo
="SpecialLogger"
name
="logger2"
>
<
lifetime
type
="singleton"
/>
</
type
>
<
type
type
="ArrayConstructor"
>
<
typeConfig
>
<
constructor
>
<
param
name
="loggers"
parameterType
="ILoggerArray"
>
<
array
>
<
dependency
name
="logger2"
/>
<
dependency
name
="logger1"
/>
</
array
>
</
param
>
</
constructor
>
</
typeConfig
>
</
type
>
</
types
>
</
container
>
未完待续。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。