依赖注入容器Unity Application Block快速入门
概述
Unity是微软模式与实践团队开发的一个轻量级、可扩展的依赖注入容器,之前我也有过一篇文章《Enterprise Library 4.0中的依赖注入容器(Unity)预览》对其做过介绍。微软模式与时间团队已经在2月份发布了Unity February 2008 CTP版本,官方主页是:http://www.codeplex.com/unity,大家可以到网站上去下载相关的源代码。本文将通过一些示例让您对Unity使用有一个逐步的认识和了解。
准备相关代码
为了接下来的说明,我们先编写几个后面需要的接口和类:
接口ILogger
public interface ILogger { void Write(string message); }
FlatFileLogger类
public class FlatFileLogger : ILogger { public void Write(string message) { Console.WriteLine(String.Format("Message:{0}", message)); Console.WriteLine("Target:FlatFile"); } }
public class DatabaseLogger : ILogger { public void Write(string message) { Console.WriteLine(String.Format("Message:{0}",message)); Console.WriteLine("Target:Database"); } }
创建容器
在Unity中创建容器实例有两种方法,一是直接使用构造函数创建,如下代码所示:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); } }
第二种通过父容器创建容器,在Unity中提供了层级容器的创建,即可以通过父容器来逐级创建容器:
图1 Unity中层级容器
通过父容器来创建容器可以使用CreateChildContainer:
class Program { static void Main(string[] args) { UnityContainer parentContainer = new UnityContainer(); UnityContainer childContainer = parentContainer.CreateChildContainer(); } }
采用层级容器的好处是我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。
class Program { static void Main(string[] args) { UnityContainer parentContainer = new UnityContainer(); UnityContainer childContainer = parentContainer.CreateChildContainer(); // can use both generated objects here // Dispose child container childContainer.Dispose(); // can use only object in parent container here // Dispose parent container parentContainer.Dispose(); } }
注册接口映射
在Unity中提供了Register方法供我们在容器中注册接口映射:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, DatabaseLogger>(); container.Register<ILogger, FlatFileLogger>("flatfileLogger"); } }
第一个泛型参数是基类型,第二个泛型参数是组件类型,它们之间必须满足一定的泛型约束关系:
IUnityContainer Register<TFrom, TTo>() where TTo : TFrom;
另外,如果在注册组件时没有指定我们也可以使用非泛型的Register方法进行接口映射:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer();
container.Register(typeof(ILogger),typeof(DatabaseLogger)); container.Register(typeof(ILogger),typeof(FlatFileLogger),"flatfileLogger"); } }
获取对象实例
在Unity中提供了Get方法用以获取对象实例,如下代码所示:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, FlatFileLogger>(); ILogger logger = container.Get<ILogger>(); logger.Write("TerryLee"); } }
在上面代码中,我们在容器中注册了一个ILogger接口到FlatFileLogger的映射,当调用Get<ILogger>()方法时,将返回ILogger的一个默认的类型实例。运行代码可以看到:
在之前注册接口映射部分,Register方法有一个重载是为接口映射指定一个特定的名称,这样我们可以根据名称和接口来获取一个特定类型的对象实例,如下面的代码我们同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并未DatabaseLogger指定一个名称,在使用Get方法的时候就可以通过ILogger和指定的名称来获取DatabaseLogger实例:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, FlatFileLogger>(); container.Register<ILogger, DatabaseLogger>("databaseLogger"); ILogger logger = container.Get<ILogger>("databaseLogger"); logger.Write("TerryLee"); } }
再运行代码,可以看到获取到了DatabaseLogger实例:
如果我们同时同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并且不指定任何名称,那么直接调用Get方法将会返回后注册的组件的对象实例,如下面的代码:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, FlatFileLogger>(); container.Register<ILogger, DatabaseLogger>(); ILogger logger = container.Get<ILogger>(); logger.Write("TerryLee"); } }
运行后会返回DatabaseLogger实例:
当然我们也可以使用非泛型的Get方法来获取对象实例:
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, FlatFileLogger>(); ILogger logger = container.Get(typeof(ILogger)) as ILogger; logger.Write("TerryLee"); } }
获取所有对象实例
除了可以获取单个对象实例之外,我们还可以一次获取容器中所有与某一接口映射的所有对象实例,但是需要依赖于在注册映射时提供的名称,如果没有指定名称,通过GetAll方法不会被获取到。
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.Register<ILogger, FlatFileLogger>(); container.Register<ILogger, FlatFileLogger>("flatFileLogger"); container.Register<ILogger, DatabaseLogger>("DatabaseLogger");
IEnumerable<ILogger> loggers = container.GetAll<ILogger>(); foreach (ILogger logger in loggers) { if (null != logger) { Console.WriteLine(logger.GetType().ToString()); } } } }运行后如下,第一个没有提供名称的类型实例不会被获取到:
结束语
关于Unity的一个简单使用就到这里了,希望能够对大家有用。使用Unity简单来说分为创建容器、注册接口映射、获取对象实例这样三步,在下篇文章中,将会说到如何使用配置文件注册接口映射以及如何注册Singleton实例等内容。
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
目前还没有看到发布的具体时间,其实EL4.0除了增加了Unity之外,其他的都是一些小的改动:)
在本文中没有发现
写“Target:FlatFile” 的代码
怎么在 图中 就输出了 这个 Target:FlatFile 的字符串呢?
另外 您的文章非常的好 。让咱受益匪浅。 不过对于愚钝浅薄的我来讲。
依赖注入 还是比较模糊的概念。 虽然上面的代码都能看懂 但是依然不能体会 这个东西给开发带来的好处。 希望兄长 以后的文中能顺带提点几句,以助末学,不胜感激。
TerryLee: @xingd
目前还没有看到发布的具体时间,其实EL4.0除了增加了Unity之外,其他的都是一些小的改动:)
--------------------------------------------------------
在 http://blogs.msdn.com/agile/archive/2007/12/03/making-dependency-injection-simpler-in-entlib-4.aspx 里,回复的时候提到是at the end of February - March 2008.
想用Entlib 4.0里的IoC,还在等待。
在准备相关代码一节里面,可以看DatabaseLogger和FlatFileLogger类的实现
关于依赖注入已经提出好长时间了,网上也有大量的资料可供参考,以后的文章我会注意这一点:)
EL4中的IOC不就是Unity吗?最终将以两种方式发布:作为EL4的一部分和作为一个独立的应用程序块。
不知道月底EL4会不会按时发布。。。
泼泼水:要是有深入的东西就好了
http://wiki.entlib.net.cn/grigori_melniks_blog_in_chinese_2008_2_12.ashx
借地方问个asp.net MVC的问题,就是Scott那个例子里面的,在ListView里面使用Html.ActionLink来生成的情况,(用内联方法可以)会报编译错误。一直解决不了,如果可以的话能不能帮助我一下,谢谢
我是想一起就学了,的确有本末倒置的嫌疑^_^ 但我相信很多人是从技术到原理,比如先听说ASP.NET MVC,才开始去了解MVC。
呵呵,我不认为这是好的学习习惯,对于MVC我相信绝大多数人是先了解的MVC,然后才接触ASP.NET MVC Framework.
有个同学(weidagang2046 )已经提出了问题,但博主的反驳确实搞笑。有问题就是有问题,应该勇于承认。
显然对于IOC容器来说,我们希望看到的是:
container.Register<ILogger>("flatfileLogger"),框架可以通过键值去配置文件里寻找具体的实现,这样我们的UI层才不会依赖于具体的类。
但我们在程序中看到的是:
container.Register<ILogger, FlatFileLogger>("flatfileLogger");
这说明,你的Program直接引用了具体的现实,这当然容易引起别人的误解,别人当然就会认为这个框架没得用了!
在任何一个IOC容器中,都会提供有两种方式,代码加入注册组件或者使用配置文件注册组件,有时候我们会根据实际需要选用。本文之所以出现误解,是因为注册组件和从容器中获取组件放在了同一段代码中。
使用下面这种方式意义不是很大:
container.Register<ILogger>("flatfileLogger")
准确的应该是:
container.Register("config.xml");
// 当然我不知道Unity中是否支持这种写法
的内容出来了吗?我怎么找不到?
希望能拜读一下!
的内容出来了吗?我怎么找不到?
希望能拜读一下!