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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

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

本篇文章将主要介绍:

1、构造函数注入。

2、属性注入。

3、方法注入。

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

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

 

一、构造函数注入

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

1
2
3
4
5
public  Subject2(MyClass myClass1,MyClass myClass2)
{
     myClass1.Name = "班级1" ;
     myClass2.Name = "班级2" ;
}

可以看到这个构造函数有2个参数,都依赖于MyClass类,如果一般情况下想要调用,我们总是需要实现构建好2个myclass对象,所以相对来说比较麻烦,而如果使用Unity来调用就会方便许多,如下代码:

1
container.Resolve<Subject2>();

仅仅一行既可,Unity容器会自动帮我们构建好所需的依赖对象实例。

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

1
2
3
4
public  Subject2(IClass myClass1)
{
     myClass1.Name = "班级1" ;
}

这样Subject2类的构造函数仅仅依赖于IClass接口,并依赖于具体的实现类,这种情况下,如果想调用的话,需要实现注册好对象之间的关系,如下代码:

1
2
3
4
5
6
7
public  static  void  ConstructorInjection()
{
     //container.Resolve<Subject2>();
 
     container.RegisterType<IClass, MyClass>();
     container.Resolve<Subject2>();
}

通过Unity容器对象的获取对象时候默认总是获取非命名默认注册对象,但是如果调用Subject2的构造函数参数我想指定具体的对象时怎么办?

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

1
2
3
4
5
public  Subject2([Dependency( "your" )]
     IClass classInfo)
{
     classInfo.Name = "班级1" ;
}

调用代码:

1
2
3
container.RegisterType<IClass, MyClass>()
     .RegisterType<IClass, YourClass>( "your" );
container.Resolve<Subject2>();

可以看到,我对IClass注册了2个对象,而我在Subject2的构造函数参数上使用了Dependency特性指定了ClassInfo参数获取注册名为“your”的对象。

 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
[InjectionConstructor]
public  Subject2([Dependency( "your" )]
     IClass classInfo)
{
     classInfo.Name = "班级1" ;
}
 
public  Subject2(IClass classInfo1, IClass classInfo2)
{
     classInfo1.Name = "班级1" ;
     classInfo2.Name = "班级2" ;
}

Unity只会调用标识了InjectionConstructor特性的构造函数,这样就很好的解决了多构造函数的情况下,Unity调用哪个构造函数。

 

二、属性注入

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  class  MyClass : IClass
{
     public  MyClass()
     {
     }
 
     public  void  ShowInfo()
     {
         Console.WriteLine( "这个是我的班级" );
     }
 
     [Dependency( "Subject1" )]
     public  ISubject Subject { get ; set ; }
 
     public  string  Name { get ; set ; }
 
     public  string  Description { get ; set ; }
}

具体的调用代码:

1
2
3
4
5
6
7
public  static  void  PropertyInjection()
{
     container.RegisterType<ISubject, Subject1>( "Subject1" )
         .RegisterType<IClass,MyClass>();
     var  classInfo = container.Resolve<IClass>();
     Console.WriteLine(classInfo.Subject.Name);
}

这样ClassInfo的Subject属性自动关联到了Subject1类上(完成了属性注入),访问classInfo.Subject.Name可以得到“科目1”。

 

三、方法注入

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public  class  MyClass : IClass
{
     public  MyClass()
     {
     }
 
     public  MyClass(ISubject subjectInfo)
     {
         this .TempSubject1 = subjectInfo;
     }
 
     public  void  ShowInfo()
     {
         Console.WriteLine( "构造注入成功后临时科目1名称:"  + this .TempSubject1.Name);
         Console.WriteLine( "属性注入成功后临时科目名称:"  + this .Subject.Name);
         Console.WriteLine( "方法注入成功后临时科目2名称:"  + this .TempSubject2.Name);
     }
 
     [InjectionMethod]
     public  void  Init(ISubject subjectInfo)
     {
         TempSubject2 = subjectInfo;
     }
 
     [Dependency( "Subject1" )]
     public  ISubject Subject { get ; set ; }
 
     public  ISubject TempSubject1 { get ; set ; }
     public  ISubject TempSubject2 { get ; set ; }
 
     public  string  Name { get ; set ; }
 
     public  string  Description { get ; set ; }
}

具体的调用代码:

1
2
3
4
5
6
7
8
9
public  static  void  MethodInjection()
{
     container.RegisterType<ISubject, Subject3>( "Subject1" )
         .RegisterType<ISubject, Subject4>();
     container.RegisterType<IClass, MyClass>();
 
     var  classInfo = container.Resolve<IClass>();
     classInfo.ShowInfo();
}

效果图如下:

pic81

 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--依赖注入配置,包括构造注入,方法注入和属性注入-->
< alias  alias="IClass" type="UnityStudyConsole.IDemo.IClass, UnityStudyConsole" />
< alias  alias="MyClass" type="UnityStudyConsole.Demo.MyClass, UnityStudyConsole" />
< alias  alias="ISubject" type="UnityStudyConsole.IDemo.ISubject, UnityStudyConsole" />
< alias  alias="Subject3" type="UnityStudyConsole.Demo.Subject3, UnityStudyConsole" />
< alias  alias="Subject4" type="UnityStudyConsole.Demo.Subject4, UnityStudyConsole" />
< container  name="Third">
   < register  type="IClass" mapTo="MyClass">
     < constructor >
       < param  name="subjectInfo" type="ISubject">
         < dependency  name="subjectInfo" type="Subject4"/>
       </ param >
     </ constructor >
     < method  name="Init">
       < param  name="subjectInfo" type="ISubject">
         < dependency  name="subjectInfo" type="Subject4"/>
       </ param >
     </ method >
     < property  name="Subject">
       < dependency  name="Subject1" type="Subject3"/>
     </ property >
   </ register >
</ container >

代码如下:

1
2
3
4
5
6
7
public  static  void  DIConfiguration()
{          
     //获取特定配置节下已命名的配置节<container name="Third">下的配置信息
     container.LoadConfiguration( "Third" );
     var  classInfo = container.Resolve<IClass>();
     classInfo.ShowInfo();
}

具体的效果是和上面截图中是一样的,只不过这边的依赖注入是通过配置文件来实现的。

 

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

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

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

1
2
3
4
5
6
7
8
9
10
11
public  static  void  BuildUp()
{
     //事先注册好ISubject和MySubject之间的关系
     //并指定一个名称以方便在接口中的属性上应用[Dependency("Subject1")]特性
     //具体请见IDemo.IClass
     container.RegisterType<ISubject, Subject1>( "Subject1" );
     IClass classInfo = new  MyClass();
     IClass classInfo2 = container.BuildUp<IClass>(classInfo);
     Console.WriteLine(classInfo2.Subject.Name);
}
#endregion

在上面的代码中,已经创建好一个对象实例了,这时只需将这个对象作为参数放入BuildUp中,同时还需指定这个对象实例所实现的接口或父类类型,这样Unity就会自动帮我们将这个已存在对象实例中各种注入。

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

 

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

pic82

 

示例代码下载:点我下载

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

 

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

第一步、基本入门

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

第十步、使用Unity解耦你的系统—PART4——Unity&PIAB

扩展学习:

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



本文转自kyo-yo博客园博客,原文链接:http://www.cnblogs.com/kyo-yo/archive/2010/11/29/Learning-EntLib-Tenth-Decoupling-Your-System-Using-The-Unity-PART3-Dependency-Injection.html,如需转载请自行联系原作者


目录
相关文章
|
5月前
|
图形学 开发者 UED
Unity游戏开发必备技巧:深度解析事件系统运用之道,从生命周期回调到自定义事件,打造高效逻辑与流畅交互的全方位指南
【8月更文挑战第31天】在游戏开发中,事件系统是连接游戏逻辑与用户交互的关键。Unity提供了多种机制处理事件,如MonoBehaviour生命周期回调、事件系统组件及自定义事件。本文介绍如何有效利用这些机制,包括创建自定义事件和使用Unity内置事件系统提升游戏体验。通过合理安排代码执行时机,如在Awake、Start等方法中初始化组件,以及使用委托和事件处理复杂逻辑,可以使游戏更加高效且逻辑清晰。掌握这些技巧有助于开发者更好地应对游戏开发挑战。
234 0
|
6月前
|
图形学 C# 开发者
Unity粒子系统全解析:从基础设置到高级编程技巧,教你轻松玩转绚丽多彩的视觉特效,打造震撼游戏画面的终极指南
【8月更文挑战第31天】粒子系统是Unity引擎的强大功能,可创建动态视觉效果,如火焰、爆炸等。本文介绍如何在Unity中使用粒子系统,并提供示例代码。首先创建粒子系统,然后调整Emission、Shape、Color over Lifetime等模块参数,实现所需效果。此外,还可通过C#脚本实现更复杂的粒子效果,增强游戏视觉冲击力和沉浸感。
406 0
|
6月前
|
开发者 图形学 前端开发
绝招放送:彻底解锁Unity UI系统奥秘,五大步骤教你如何缔造令人惊叹的沉浸式游戏体验,从Canvas到动画,一步一个脚印走向大师级UI设计
【8月更文挑战第31天】随着游戏开发技术的进步,UI成为提升游戏体验的关键。本文探讨如何利用Unity的UI系统创建美观且功能丰富的界面,包括Canvas、UI元素及Event System的使用,并通过具体示例代码展示按钮点击事件及淡入淡出动画的实现过程,助力开发者打造沉浸式的游戏体验。
185 0
|
6月前
|
图形学
Unity动画☀️Unity动画系统Bug集合
Unity动画☀️Unity动画系统Bug集合
|
7月前
|
数据可视化 vr&ar C#
|
8月前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
254 2
|
8月前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
124 0
|
8月前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
132 0
|
8月前
|
图形学
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
187 0
|
8月前
|
存储 JSON 图形学
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
238 0