您的位置:首页 > 移动开发 > Unity3D

(转)[EntLib]微软企业库5.0 学习之路——第十步、使用Unity解耦你的系统—PART3——依赖注入

2010-11-29 17:50 936 查看
原文地址:/article/4792194.html

继续学习Unity,在前几篇中已经将Unity的使用方法做了一个还算详细的介绍了,主要是如何通过代码及配置文件来注册对象之间的关系、Unity内置所有的生命周期管理使用介绍,及Unity的Register和Resolve的一些高级应用。通过在PART1——为什么要使用Unity?的学习我们知道Unity可以帮我们简化并管理对象之间的关系(也就是前几篇所介绍的),而今天则要介绍Unity的另外一个重要功能——DI(依赖注入)。

本篇文章将主要介绍:

1、构造函数注入。

2、属性注入。

3、方法注入。

4、使用配置完成各种注入。

5、对已经创建对象进行注入。



[b]一、构造函数注入[/b]

在有些时候,我们所编写的类中的构造函数都会包含对其他对象的引用,如下代码:

viewsourceprint?
1
public
Subject2(MyClassmyClass1,MyClassmyClass2)
2
{
3
myClass1.Name=
"班级1"
;
4
myClass2.Name=
"班级2"
;
5
}
可以看到这个构造函数有2个参数,都依赖于MyClass类,如果一般情况下想要调用,我们总是需要实现构建好2个myclass对象,所以相对来说比较麻烦,而如果使用Unity来调用就会方便许多,如下代码:

viewsourceprint?
1
container.Resolve<Subject2>();
仅仅一行既可,Unity容器会自动帮我们构建好所需的依赖对象实例。

当然这个只是简单的使用,在实际的情况下我们不会这么编写代码,我们不会直接引用对象,而是直接引用接口,这样可以解除代码的耦合性,如下代码:

viewsourceprint?
1
public
Subject2(IClassmyClass1)
2
{
3
myClass1.Name=
"班级1"
;
4
}
这样Subject2类的构造函数仅仅依赖于IClass接口,并依赖于具体的实现类,这种情况下,如果想调用的话,需要实现注册好对象之间的关系,如下代码:

viewsourceprint?
1
public
static
void
ConstructorInjection()
2
{
3
//container.Resolve<Subject2>();
4
5
container.RegisterType<IClass,MyClass>();
6
container.Resolve<Subject2>();
7
}
通过Unity容器对象的获取对象时候默认总是获取非命名默认注册对象,但是如果调用Subject2的构造函数参数我想指定具体的对象时怎么办?

这时就需要使用Dependency这个特性类来解决了,在需要特殊指定的依赖关系的参数上加上Dependency特性,并为Dependency指定好参数name(此name参数表示注册对象关系时所指定的名称),代码如下:

viewsourceprint?
1
public
Subject2([Dependency(
"your"
)]
2
IClassclassInfo)
3
{
4
classInfo.Name=
"班级1"
;
5
}
调用代码:

viewsourceprint?
1
container.RegisterType<IClass,MyClass>()
2
.RegisterType<IClass,YourClass>(
"your"
);
3
container.Resolve<Subject2>();
可以看到,我对IClass注册了2个对象,而我在Subject2的构造函数参数上使用了Dependency特性指定了ClassInfo参数获取注册名为“your”的对象。

现在还有一个问题,就是当一个类存在多个构造函数的时候,我们如何区分哪个构造函数需要实现注入,哪个不需要?

这时就可以使用InjectionConstructor特性来标识,代码如下:

viewsourceprint?
01
[InjectionConstructor]
02
public
Subject2([Dependency(
"your"
)]
03
IClassclassInfo)
04
{
05
classInfo.Name=
"班级1"
;
06
}
07
08
public
Subject2(IClassclassInfo1,IClassclassInfo2)
09
{
10
classInfo1.Name=
"班级1"
;
11
classInfo2.Name=
"班级2"
;
12
}
Unity只会调用标识了InjectionConstructor特性的构造函数,这样就很好的解决了多构造函数的情况下,Unity调用哪个构造函数。

[b]二、属性注入[/b]

属性注入和构造函数注入类似,只需在需要注入的属性上增加一个Dependency特性,同样的也可以为Dependency指定一个name参数用来指定注入属性的具体对象,如下代码,在Subject属性上增加了Dependency特性,来表示这个属性需要注入:

viewsourceprint?
01
public
class
MyClass:IClass
02
{
03
public
MyClass()
04
{
05
}
06
07
public
void
ShowInfo()
08
{
09
Console.WriteLine(
"这个是我的班级"
);
10
}
11
12
[Dependency(
"Subject1"
)]
13
public
ISubjectSubject{
get
;
set
;}
14
15
public
string
Name{
get
;
set
;}
16
17
public
string
Description{
get
;
set
;}
18
}
具体的调用代码:

viewsourceprint?
1
public
static
void
PropertyInjection()
2
{
3
container.RegisterType<ISubject,Subject1>(
"Subject1"
)
4
.RegisterType<IClass,MyClass>();
5
varclassInfo=container.Resolve<IClass>();
6
Console.WriteLine(classInfo.Subject.Name);
7
}
这样ClassInfo的Subject属性自动关联到了Subject1类上(完成了属性注入),访问classInfo.Subject.Name可以得到“科目1”。

[b]三、方法注入[/b]

方法注入同样只需在需要注入的方法上增加一个特性——InjectionMethod既可(其使用方法也和构造注入类似),这样Unity会自动帮我们完成注入,方法注入和构造注入一样,同样可以在方法的参数上指定Dependency特性来指定参数所依赖的注册,下面的类代码中包含了构造注入、属性注入及方法注入,这边集合在一起展示相对来说直观一些:

viewsourceprint?
01
public
class
MyClass:IClass
02
{
03
public
MyClass()
04
{
05
}
06
07
public
MyClass(ISubjectsubjectInfo)
08
{
09
this
.TempSubject1=subjectInfo;
10
}
11
12
public
void
ShowInfo()
13
{
14
Console.WriteLine(
"构造注入成功后临时科目1名称:"
+
this
.TempSubject1.Name);
15
Console.WriteLine(
"属性注入成功后临时科目名称:"
+
this
.Subject.Name);
16
Console.WriteLine(
"方法注入成功后临时科目2名称:"
+
this
.TempSubject2.Name);
17
}
18
19
[InjectionMethod]
20
public
void
Init(ISubjectsubjectInfo)
21
{
22
TempSubject2=subjectInfo;
23
}
24
25
[Dependency(
"Subject1"
)]
26
public
ISubjectSubject{
get
;
set
;}
27
28
public
ISubjectTempSubject1{
get
;
set
;}
29
public
ISubjectTempSubject2{
get
;
set
;}
30
31
public
string
Name{
get
;
set
;}
32
33
public
string
Description{
get
;
set
;}
34
}
具体的调用代码:

viewsourceprint?
1
public
static
void
MethodInjection()
2
{
3
container.RegisterType<ISubject,Subject3>(
"Subject1"
)
4
.RegisterType<ISubject,Subject4>();
5
container.RegisterType<IClass,MyClass>();
6
7
varclassInfo=container.Resolve<IClass>();
8
classInfo.ShowInfo();
9
}
效果图如下:





[b]4、使用配置完成各种注入[/b]

上面所演示的代码都是通过代码来完成对象的注入,下面演示下如何通过配置文件来配置这些注入,具体配置代码如下:

viewsourceprint?
01
<!--依赖注入配置,包括构造注入,方法注入和属性注入-->
02
<
alias
alias
=
"IClass"
type
=
"UnityStudyConsole.IDemo.IClass,UnityStudyConsole"
/>
03
<
alias
alias
=
"MyClass"
type
=
"UnityStudyConsole.Demo.MyClass,UnityStudyConsole"
/>
04
<
alias
alias
=
"ISubject"
type
=
"UnityStudyConsole.IDemo.ISubject,UnityStudyConsole"
/>
05
<
alias
alias
=
"Subject3"
type
=
"UnityStudyConsole.Demo.Subject3,UnityStudyConsole"
/>
06
<
alias
alias
=
"Subject4"
type
=
"UnityStudyConsole.Demo.Subject4,UnityStudyConsole"
/>
07
<
container
name
=
"Third"
>
08
<
register
type
=
"IClass"
mapTo
=
"MyClass"
>
09
<
constructor
>
10
<
param
name
=
"subjectInfo"
type
=
"ISubject"
>
11
<
dependency
name
=
"subjectInfo"
type
=
"Subject4"
/>
12
</
param
>
13
</
constructor
>
14
<
method
name
=
"Init"
>
15
<
param
name
=
"subjectInfo"
type
=
"ISubject"
>
16
<
dependency
name
=
"subjectInfo"
type
=
"Subject4"
/>
17
</
param
>
18
</
method
>
19
<
property
name
=
"Subject"
>
20
<
dependency
name
=
"Subject1"
type
=
"Subject3"
/>
21
</
property
>
22
</
register
>
23
</
container
>
代码如下:

viewsourceprint?
1
public
static
void
DIConfiguration()
2
{
3
//获取特定配置节下已命名的配置节<containername="Third">下的配置信息
4
container.LoadConfiguration(
"Third"
);
5
varclassInfo=container.Resolve<IClass>();
6
classInfo.ShowInfo();
7
}
具体的效果是和上面截图中是一样的,只不过这边的依赖注入是通过配置文件来实现的。

[b]5、对已经创建对象进行注入[/b]

一般来说如果想实现依赖注入需要通过Unity容器来进行对象注册,然后通过Unity容器来获取对象,但是如果对象已经存在(就是不是通过Unity容器来获取的对象),这时如何来通过Unity来实现对已有的对象进行依赖注入呢?

Unity容器已经为我们提供好了这种情况的解决办法,就是BuildUp方法,看下下面的代码就能明白了:

viewsourceprint?
01
public
static
void
BuildUp()
02
{
03
//事先注册好ISubject和MySubject之间的关系
04
//并指定一个名称以方便在接口中的属性上应用[Dependency("Subject1")]特性
05
//具体请见IDemo.IClass
06
container.RegisterType<ISubject,Subject1>(
"Subject1"
);
07
IClassclassInfo=
new
MyClass();
08
IClassclassInfo2=container.BuildUp<IClass>(classInfo);
09
Console.WriteLine(classInfo2.Subject.Name);
10
}
11
#endregion
在上面的代码中,已经创建好一个对象实例了,这时只需将这个对象作为参数放入BuildUp中,同时还需指定这个对象实例所实现的接口或父类类型,这样Unity就会自动帮我们将这个已存在对象实例中各种注入。

需要注意的是,与上面所说3种依赖注入的不同的是,上面3中的依赖注入需要在具体的类中使用InjectionConstructor、InjectionMethodDependency和特性,而如果对已经存在的对象进行依赖注入,则需要将InjectionConstructor、InjectionMethod和Dependency写在这个对象实例所实现的接口或父类中,否则会报错!

到本文为止,Unity的各种常用功能都已经介绍完毕了,各位可以下载下面的源代码进行查看,同时也可以通过Main方法中的各个方法来查看Unity的各种功能的使用:





示例代码下载:点我下载

注意:本文示例代码是基于VS2010+Unity2.0,所以请使用VS2010打开,如果没有安装VS2010,请将相关代码复制到相应的VS中运行既可

[b]微软企业库5.0学习之路系列文章索引:[/b]

第一步、基本入门

第二步、使用VS2010+DataAccess模块建立多数据库项目

第三步、为项目加上异常处理(采用自定义扩展方式记录到数据库中)

第四步、使用缓存提高网站的性能(EntLibCaching)

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——上篇

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——中篇

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——下篇

第六步、使用Validation模块进行服务器端数据验证

第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇

第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇

第八步、使用ConfigurationSetting模块等多种方式分类管理企业库配置信息

第九步、使用PolicyInjection模块进行AOP—PART1——基本使用介绍

第九步、使用PolicyInjection模块进行AOP—PART2——自定义MatchingRule

第九步、使用PolicyInjection模块进行AOP—PART3——内置CallHandler介绍

第九步、使用PolicyInjection模块进行AOP—PART4——建立自定义CallHandler实现用户操作日志记录

第十步、使用Unity解耦你的系统—PART1——为什么要使用Unity?

第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(1)

第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(2)

第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(3)

第十步、使用Unity解耦你的系统—PART3——依赖注入

扩展学习:

扩展学习篇、库中的依赖关系注入(重构MicrosoftEnterpriseLibrary)[转]

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐
章节导航