Dorian Deng-www.doriandeng.cn

追随理想和美人而生活

博客园 首页 新随笔 联系 订阅 管理
  95 Posts :: 0 Stories :: 203 Comments :: 74 Trackbacks

原文链接:http://www.doriandeng.cn/post/2008/05/look-into-unity-1-x-quickstart.aspx

Unity 是由微软开发的一个轻量级、可扩展的依赖注入(Dependency Injection, DI)容器,支持构造函数、属性和方法的依赖注入。所谓依赖的注入,即将程序开发过程中的对象与其所依赖的具体对象解耦,从一定程度上仅关注对所依赖对象 的使用,却不管其具体对象是哪个类的实例;而真正的被依赖对象在运行时由容器注入。本质上,它就是一个对象工厂和对象管理器。更详细的信息,请参见《IoC 容器和Dependency Injection 模式》。

Unity 适用于可扩展、可插接的应用程序的开发,对于普通的、不要求插接的应用程序的开发反而会增加开发的复杂度。Unity 的使用对性能也会有少量的影响 。

准备

在本系列的文章中,我们假设有一个 Telephone 类,一个 IDialer 接口和一个 Dialer 抽象类。如下代码所示:

Unity 的初始化

Unity 容器在使用前一般需要针对所使用的对象类型进行初始化,某些时候也可以不进行初始化。Unity 容器的初始化主要是对象类型的注册。这可以用二种方法完成,一是使用 .NET 代码,另一种就是使用 XML 配置文件。在 Unity 文档的示例中,绝大多数的示例都是使用代码的方法来对 Untiy 进行初始化,这也给不少人造成了使用 Unity 容器来管理对象比直接使用更复杂的错觉。本文将同时使用代码和 XML 配置文件的方法来对初始化及其其他相关方面进行说明,以便大家对 Unity 能有更全面、更正确的认识。

类型注册

首先,在代码文件中添加对 Microsoft.Practices.Unity 命名空间的引用。

然后,可以用代码方式进行如下的注册,(其中的 ButtonTypeDialer 类包含在供下载的源代码中。):

运行结果如下:

下面,我们看看用 XML 如何来进行初始化。

首先,在配置文件中,需要添加下列配置节声明:

然后,配置类型注册:

最后,我们可以用下列的方式来使用:

由上面的代码我们可以看出,在完成 Unity 的容器初始化后,使用的方法是一样的。

 构造函数注入

实质上,上面的示例我们可以用如下代码来实现:

 这二段代码唯一的不同就是 38、39 行合并成了 52 这一行。这就是利用了构造函数注入。

在 Telephone 类中,我们声明了一个  public Telephone(IDialer dialer) 的构造函数,而在 Unity 容器中,已进行了用于 IDialer 接口的注册,所以在使用 Unity 容器的 Resolve 方法获取对象时,就自动调用了此构造函数对对象进行了初始化。如果不存在这样的构造函数,Unity 容器将自动调用其默认构造函数进行初始化。

如果同时存在多个带参数的构造函数,就需要用 [InjectionConstructor] 特性来指定将使用的构造函数。

属性注入

要使用属性注入,我们需要在 Telephone 类的 Dialer 属性上加上 [Dependency] 特性声明,如下所示:

 同时,在配置文件中加入如下配置以注册 Dialer 抽象类的映射:

这样,构造函数注入中的示例代码就依然是有效的,虽然构造函数已被注释掉了。

方法调用注入

我们对 Telephone 类做进一步的修改,注释掉 [Dependency] 特性,添加一个 Initialize 方法:

在 Initialize 方法上,我们加上了 [InjectionMethod] 以指出使用了方法调用注入的方法。这也使得在构造函数注入中所使用的示例代码依然有效。

总结

Unity 是一个轻量级、可扩展的 DI 容器,它可以用代码或配置文件来进行类型的注册,同时支持构造函数注入、属性注入和方法调用注入。


更多信息,请参考《Unity 1.x 中文文档》。

源代码下载

look-into-unity-1-x.zip

希望对您有所帮助!

邓明

理想&美人.NET 藏经阁论坛

posted on 2008-05-21 01:13 Dorian Deng 阅读(2143) 评论(27)  编辑 收藏 所属分类: .NETUnity

Feedback

#1楼  2008-05-21 01:26 皇帝的新装      
看看谁解释的最好
  回复  引用  查看    

#2楼  2008-05-21 08:09 小庄      
呵呵,同意楼上
  回复  引用  查看    

#3楼  2008-05-21 09:10 b4nc [未注册用户]
>>虽然属性注入和方法调用注入必须使用特性进行声明,侵入了其他独立的组件,但这二种方法都可以用构造函数注入所代替,所以在设计上并无不可。

这种设计问题多多。

假设你需要注入n个对象,难道写一个超长的构造函数??
我就不理解,为什么spring就可以做的到,ms就做不到?这完全不存在技术上无法实现的问题。
  回复  引用    

#4楼 [楼主] 2008-05-21 10:00 Dorian Deng      
@b4nc
需要构造函数超长的情况实质上很少出现,如果出现这种情况,就应该首先考虑是不是自己的设计上存在问题了。
  回复  引用  查看    

#5楼  2008-05-21 10:16 Clark Zheng      
@b4nc
不知所云,Unity也支持属性注入和方法调用注入呀
  回复  引用  查看    

#6楼  2008-05-21 10:46 ganquan [未注册用户]
加密混淆后,类名、属性名、方法名全部变了,还怎么注入?
大部分人都好像不关心加密,都是做网站的?
  回复  引用    

#7楼  2008-05-21 12:16 b4nc [未注册用户]
--引用--------------------------------------------------
Clark Zheng: @b4nc
不知所云,Unity也支持属性注入和方法调用注入呀
--------------------------------------------------------
这位仁兄,有没有看清楚讨论的重点?是非侵入式注射。


--引用--------------------------------------------------
Dorian Deng: @b4nc
需要构造函数超长的情况实质上很少出现,如果出现这种情况,就应该首先考虑是不是自己的设计上存在问题了。
--------------------------------------------------------
问题是,我现在想非侵入式注射多个对象,在Unity里只能采用这种超长的构造函数。

我一直感觉不理解的是,像属性,方法注射,在技术上完全可以做到非侵入的,为什么现在需要依赖于Unity?
或许我只能期待Untiy的下一个版本了。
  回复  引用    

#8楼  2008-05-21 12:26 高海东      
很好
  回复  引用  查看    

#9楼  2008-05-21 12:26 高海东      
依赖
  回复  引用  查看    

#10楼 [楼主] 2008-05-21 12:43 Dorian Deng      
@ganquan
每种方法都有其适用范围,只能说 Unity 不适用于你。

另外,不要看不起做网站的、Web 应用开发的和 B/S 架构企业应用开发的,Unity 同样适用于其他很多情况。
  回复  引用  查看    

#11楼 [楼主] 2008-05-21 12:45 Dorian Deng      
@b4nc
如果一定需要这样,可以考虑用 Spring.NET。没有人要求你一定使用 Unity。
  回复  引用  查看    

#12楼  2008-05-21 13:48 b4nc [未注册用户]
--引用--------------------------------------------------
Dorian Deng: @b4nc
如果一定需要这样,可以考虑用 Spring.NET。没有人要求你一定使用 Unity。
--------------------------------------------------------

貌似lz容不得别人对Unity有不同看法啊。
我不是说一定要这样,而只是讨论一个基本的技术问题,既然lz都这么表态了,那我不再说了行了吧。
  回复  引用    

#13楼 [楼主] 2008-05-21 14:14 Dorian Deng      
@b4nc
你会错我的意思了,我只是说没有人要求你在不合适的时机使用 Unity,它不过是一个工具,解决不了你的问题,当然可以使用其他的。与其在此讨论某个框架多不好,某个框架多好,不如好好讨论下在哪种环境可以发挥更好的作用,而哪些情况下不适用使用。

另外,我的看法是什么?你的看法又是什么?有什么不同?奇怪,好像并没有什么不同。

Unity 的确不适用于你所说的情况,可在某些地方,使用它却很合适。学会合理的使用一个工具,而不是抓住一个缺点就否定全部。
  回复  引用  查看    

#14楼  2008-05-21 15:54 紫色阴影      
@Dorian Deng
Unity还是不错的
和Guice有点像,Guice利用annotation,Unity使用attribute
的确侵入性非常强,到处需要引用第三方的库,如别人所说的“简直是侵略”
但是可以用设计来避免这个问题
  回复  引用  查看    

#15楼  2008-05-21 17:24 浪子      
Clark Zheng兄已经回答了你的问题。

使用属性注入即可,并不需要如你说的那样子,超长构造函数^_^

--引用--------------------------------------------------
b4nc: --引用--------------------------------------------------
Clark Zheng: @b4nc
不知所云,Unity也支持属性注入和方法调用注入呀
--------------------------------------------------------
这位仁兄,有没有看清楚讨论的重点?是非侵入式注射。


--引用--------------------------------------------------
Dorian Deng: @b4nc
需要构造函数超长的情况实质上很少出现,如果出现这种情况,就应该首先考虑是不是自己的设计上存在问题了。
--------------------------------------------------------
问题是,我现在想非侵入式注射多个对象,在Unity里只能采用这种超长的构造函数。

我一直感觉不理解的是,像属性,方法注射,在技术上完全可以做到非侵入的,为什么现在需要依赖于Unity?
或许我只能期待Untiy的下一个版本了。
--------------------------------------------------------

  回复  引用  查看    

#16楼  2008-05-21 17:31 紫色阴影      
@浪子
using Microsoft.Practices.Unity;
这就算是侵入了
  回复  引用  查看    

#17楼  2008-05-21 18:01 浪子      
明白了,b4nc是要做完全的零耦合啊。

不过没仔细衡量过这样子做是为了解决什么问题?似乎没人整天换IoC容器?

--引用--------------------------------------------------
紫色阴影: @浪子
using Microsoft.Practices.Unity;
这就算是侵入了
--------------------------------------------------------

  回复  引用  查看    

#18楼  2008-05-21 18:06 紫色阴影      
如果现在有一大堆code存在,而需要加上IOC,难道要所有需要注入的地方都得改code?
而且非侵入性的也容易替换

--引用--------------------------------------------------
浪子: 明白了,b4nc是要做完全的零耦合啊。

不过没仔细衡量过这样子做是为了解决什么问题?似乎没人整天换IoC容器?
--------------------------------------------------------

  回复  引用  查看    

#19楼 [楼主] 2008-05-21 19:16 Dorian Deng      
@紫色阴影
是否被侵入是针对服务提供对象而言的,对于服务使用对象进行这样的讨论没有意义。

  回复  引用  查看    

#20楼  2008-05-21 20:40 紫色阴影      
@Dorian Deng
为什么没有意义?为什么我的代码要依赖于Unity的API呢
  回复  引用  查看    

#21楼  2008-05-21 22:01 浪子      
嗯.没错.

所以说对于需要非侵入性的IoC容器,适用两个场景:

1.现有程序,需要加入IoC来做对象注入
2.可以预见未来有可能会替换IoC容器的provider

如果这两种情况就需要非侵入性的.

--引用--------------------------------------------------
紫色阴影: 如果现在有一大堆code存在,而需要加上IOC,难道要所有需要注入的地方都得改code?
而且非侵入性的也容易替换

--引用--------------------------------------------------
浪子: 明白了,b4nc是要做完全的零耦合啊。

不过没仔细衡量过这样子做是为了解决什么问题?似乎没人整天换IoC容器?
--------------------------------------------------------

--------------------------------------------------------

  回复  引用  查看    

#22楼  2008-05-21 22:02 浪子      
@紫色阴影

想知道.net/java底下哪些IoC容器是非侵入性,thanks in advance.^_^
  回复  引用  查看    

#23楼 [楼主] 2008-05-22 06:45 Dorian Deng      
@紫色阴影
我指的是示例中的 Program 类,假如要在其中使用 Unity 来获取对象,如果不用其 API,又如何称为使用了 Unity?好绕的问题

如果连 DI 容器也要求可替换的,那就需要自己写代码来做成 Provider,这不就将问题复杂了,也失去了使用 DI 的好处。
  回复  引用  查看    

#24楼  2008-05-22 10:46 紫色阴影      
@浪子
Spring/Spring.Net 算是比较好的 Java下还有一堆 :)
  回复  引用  查看    

#25楼  2008-05-22 10:53 紫色阴影      
@Dorian Deng
DI可替换是经常会遇到的。
Program类使用Unity是没有问题的,但是上面所写的方法是从容器中获得对象显式给属性赋值,不够透明
要透明的话被注入的类的属性就得加上[Dependency]吧,这样又太侵入了
当然这里可以用Factory
这篇文章有些观点说得很好http://ayende.com/Blog/archive/2008/02/24/Reviewing-Unity.aspx

  回复  引用  查看    

#26楼  2008-05-22 12:28 紫色阴影      
@Dorian Deng
不过很多人不喜欢Xml配置,就喜欢用Attribute 呵呵
  回复  引用  查看    

#27楼 [楼主] 2008-05-22 23:53 Dorian Deng      
@浪子
@紫色阴影
@b4nc
以上我们讨论的问题,我会在《深入 Unity 1.x 之四》中给出一个满意的答案,而且是一个大家都期待的答案。
  回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-05-23 07:30 编辑过