C# Unity 依赖注入

看了挺长时间框架搭建,今天看到一篇博客突然顿悟了依赖注入!

控制反转(Ioc)可以看成自来水厂,那自来水厂的运行就可以看作依赖注入(DI),Ioc是一个控制容器,DI就是这个容器的运行机制,有点像国家主席和总理的意思。

(  Ioc  主要功能是提供各种方法,但是具体要提供什么样的方法就要靠   DI 依赖注入了。就像自来水厂虽然是提供水的,它控制着水在大众视野中的提供者,但是自来水厂的水却是靠自己的地下水或者是其他方提供的)

构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象。

 1 /// <summary>
 2         /// 人接口
 3         /// </summary>
 4         public interface IPeople
 5         {
 6             void DrinkWater();
 7         }
 8         /// <summary>
 9         /// 村民
10         /// </summary>
11         public class VillagePeople : IPeople
12         {
13             IWaterTool _pw;
14             public VillagePeople(IWaterTool pw)
15             {
16                 _pw = pw;
17             }
18             public void DrinkWater()
19             {
20                 Console.WriteLine(_pw.returnWater());
21             }
22         }
23         /// <summary>
24         /// 压水井
25         /// </summary>
26         public class PressWater : IWaterTool
27         {
28             public string returnWater()
29             {
30                 return "地下水好甜啊!!!";
31             }
32         }
33         /// <summary>
34         /// 获取水方式接口
35         /// </summary>
36         public interface IWaterTool
37         {
38             string returnWater();
39         }

简单调用一下

1 static void Main(string[] args)
2         {
3             UnityContainer container = new UnityContainer();//创建容器
4             container.RegisterType<Test01.IWaterTool, Test01.PressWater>();//注册依赖对象
5             Test01.IPeople people = container.Resolve<Test01.VillagePeople>();//返回调用者
6             people.DrinkWater();//喝水
7         }

关于RegisterType和Resolve我们可以用自来水厂的例子来说明,请看下面:

  • RegisterType:可以看做是自来水厂决定用什么作为水源,可以是水库或是地下水,我只要“注册”开关一下就行了。
  • Resolve:可以看做是自来水厂要输送水的对象,可以是农村或是城市,我只要“控制”输出就行了。

属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性。

属性注入只需要在属性字段前面加[Dependency]标记就行了,如下:

 1 /// <summary>
 2         /// 村民
 3         /// </summary>
 4         public class VillagePeople02 : IPeople
 5         {
 6             [Dependency]
 7             public IWaterTool _pw { get; set; }
 8             public void DrinkWater()
 9             {
10                 Console.WriteLine(_pw.returnWater());
11             }
12         }

调用方式和构造器注入一样,通过RegisterType<Test02.IWaterTool, Test02.PressWater>();注入就可以了,除了使用RegisterType方法注册,我们还可以在配置文件中注册,[Dependency]和RegisterType方式其实都会产生耦合度,我们要添加一个属性或是修改一中注册都会去修改代码,我们要做的就是代码不去修改,只要修改配置文件了,这个在下面有讲解,这边就不多说,我们先看下使用UnityConfigurationSection的Configure方法加载配置文件注册:

1 <unity>
2     <containers>
3       <container name="defaultContainer">
4         <register type="UnityContainerDemo.IWaterTool,UnityContainerDemo" mapTo="UnityContainerDemo.PressWater,UnityContainerDemo"/>
5         <register type="UnityContainerDemo.IPeople,UnityContainerDemo" mapTo="UnityContainerDemo.VillagePeople02,UnityContainerDemo"/>
6       </container>
7     </containers>
8   </unity>
1 public static void FuTest02()
2         {
3             UnityContainer container = new UnityContainer();//创建容器
4             UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
5             configuration.Configure(container, "defaultContainer");
6             IPeople people = container.Resolve<IPeople>();//返回调用者
7             people.DrinkWater();//喝水
8         }

方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。

方法注入和属性方式使用一样,方法注入只需要在方法前加[InjectionMethod]标记就行了,从方法注入的定义上看,只是模糊的说对某个方法注入,并没有说明这个方法所依赖的对象注入,所依赖的对象无非就三种:参数、返回值和方法内部对象引用,我们做一个示例试下:

 1 /// <summary>
 2     /// 村民
 3     /// </summary>
 4     public class VillagePeople03 : IPeople
 5     {
 6         public IWaterTool tool;//我是对象引用
 7         public IWaterTool tool2;//我是参数
 8         public IWaterTool tool3;//我是返回值
 9         [InjectionMethod]
10         public void DrinkWater()
11         {
12             if (tool == null)
13             { }
14         }
15         [InjectionMethod]
16         public void DrinkWater2(IWaterTool tool2)
17         {
18             this.tool2 = tool2;
19         }
20         [InjectionMethod]
21         public IWaterTool DrinkWater3()
22         {
23             return tool3;
24         }
25     }
 1 public static void FuTest03()
 2         {
 3             UnityContainer container = new UnityContainer();//创建容器
 4             UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
 5             configuration.Configure(container, "defaultContainer");
 6             VillagePeople03 people = container.Resolve<IPeople>() as VillagePeople03;//返回调用者
 7             Console.WriteLine("people.tool == null(引用) ? {0}", people.tool == null ? "Yes" : "No");
 8             Console.WriteLine("people.tool2 == null(参数) ? {0}", people.tool2 == null ? "Yes" : "No");
 9             Console.WriteLine("people.tool3 == null(返回值) ? {0}", people.tool3 == null ? "Yes" : "No");
10         }

container.Resolve<IPeople>() as VillagePeople03;其实多此一举,因为已经在配置文件注册过了,不需要再进行转化,这边只是转化只是方便访问VillagePeople03对象的几个属性值

除了我们上面使用RegisterType和Resolve泛型方法,我们也可以使用非泛型注入,代码如下:

1 public static void FuTest04()
2         {
3             UnityContainer container = new UnityContainer();//创建容器
4             container.RegisterType(typeof(IWaterTool), typeof(PressWater));//注册依赖对象
5             IPeople people = (IPeople)container.Resolve(typeof(VillagePeople01));//返回调用者
6             people.DrinkWater();//喝水
7         }

为了实现单例模式,我们通常的做法是,在类中定义一个方法如GetInstance,判断如果实例为null则新建一个实例,否则就返回已有实例。但是我觉得这种做法将对象的生命周期管理与类本身耦合在了一起。所以我觉得遇到需要使用单例的地方,应该将生命周期管理的职责转移到对象容器Ioc上,而我们的类依然是一个干净的类,使用Unity创建单例代码:

1 public static void FuTest07()
2         {
3             UnityContainer container = new UnityContainer();//创建容器
4             container.RegisterType<IWaterTool, PressWater>(new ContainerControlledLifetimeManager());//注册依赖对象
5             IPeople people = container.Resolve<VillagePeople01>();//返回调用者
6             people.DrinkWater();//喝水
7         }

上面演示了将IWaterTool注册为PressWater,并声明为单例,ContainerControlledLifetimeManager字面意思上就是Ioc容器管理声明周期,我们也可以不使用类型映射,将某个类注册为单例:

1 container.RegisterType<PressWater>(new ContainerControlledLifetimeManager());

除了将类型注册为单例,我们也可以将已有对象注册为单例,使用RegisterInstance方法,示例代码:

1 PressWater pw = new PressWater();
2  container.RegisterInstance<IWaterTool>(pw);

上面的代码就表示将PressWater的pw对象注册到Ioc容器中,并声明为单例。

  如果我们在注册类型的时候没有指定ContainerControlledLifetimeManager对象,Resolve获取的对象的生命周期是短暂的,Ioc容器并不会保存获取对象的引用,就是说我们再次Resolve获取对象的时候,获取的是一个全新的对象,如果我们指定ContainerControlledLifetimeManager,类型注册后,我们再次Resolve获取的对象就是上次创建的对象,而不是再重新创建对象,这也就是单例的意思。

这种配置都会产生耦合度,比如添加一个属性注入或是方法注入都要去属性或是方法前加[Dependency]和[InjectionMethod]标记,我们想要的依赖注入应该是去配置文件中配置,当系统发生变化,我们不应去修改代码,而是在配置文件中修改,这才是真正使用依赖注入解决耦合度所达到的效果,先看下Unity完整的配置节点:

 1 <?xml version="1.0"?>
 2 <configuration>
 3   <configSections>
 4     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
 5              Microsoft.Practices.Unity.Configuration" />
 6   </configSections>
 7   <typeAliases>
 8     <!--寿命管理器类型-->
 9     <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" />
10     <typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity" />
11     <!--用户定义的类型别名-->
12     <typeAlias alias="IMyInterface" type="MyApplication.MyTypes.MyInterface, MyApplication.MyTypes" />
13     <typeAlias alias="MyRealObject" type="MyApplication.MyTypes.MyRealObject, MyApplication.MyTypes" />
14     <typeAlias alias="IMyService" type="MyApplication.MyTypes.MyService, MyApplication.MyTypes" />
15     <typeAlias alias="MyDataService" type="MyApplication.MyTypes.MyDataService, MyApplication.MyTypes" />
16     <typeAlias alias="MyCustomLifetime" type="MyApplication.MyLifetimeManager, MyApplication.MyTypes" />
17   </typeAliases>
18   <unity>
19   <containers>
20     <container name="containerOne">
21       <types>
22         <!--类型映射无一生-默认为“瞬时”-->
23         <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass" />
24         <!--使用上面定义的别名类型的映射-->
25         <type type="IMyInterface" mapTo="MyRealObject" name="MyMapping" />
26         <!--使用类型别名指定的终身-->
27         <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass">
28           <lifetime type="singleton" />
29         </type>
30         <type type="IMyInterface" mapTo="MyRealObject" name="RealObject">
31           <lifetime type="external" />
32         </type>
33         <!--使用完整的类型名指定终身经理-->
34         <!--的一生经理指定的任何初始化数据-->
35         <!--将要使用的默认类型转换器转换-->
36         <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass">
37           <lifetime value="sessionKey" type="MyApplication.MyTypes.MyLifetimeManager,MyApplication.MyTypes" />
38         </type>
39         <!--使用一个自定义TypeConverter的终身管理器初始化-->
40         <type type="IMyInterface" mapTo="MyRealObject" name="CustomSession">
41           <lifetime type="MyCustomLifetime" value="ReverseKey" typeConverter="MyApplication.MyTypes.MyTypeConverter,MyApplication.MyTypes" />
42         </type>
43         <!--对象在配置中定义的注入参数-->
44         <!--使用上面定义的别名类型的映射-->
45         <type type="IMyService" mapTo="MyDataService" name="DataService">
46           <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
47             <constructor>
48               <param name="connectionString" parameterType="string">
49                 <value value="AdventureWorks"/>
50               </param>
51               <param name="logger" parameterType="ILogger">
52                 <dependency />
53               </param>
54             </constructor>
55             <property name="Logger" propertyType="ILogger" />
56             <method name="Initialize">
57               <param name="connectionString" parameterType="string">
58                 <value value="contoso"/>
59               </param>
60               <param name="dataService" parameterType="IMyService">
61                 <dependency />
62               </param>
63             </method>
64           </typeConfig>
65         </type>
66       </types>
67
68       <instances>
69         <add name="MyInstance1" type="System.String" value="Some value" />
70         <add name="MyInstance2" type="System.DateTime" value="2008-02-05T17:50:00" />
71       </instances>
72
73       <extensions>
74         <add type="MyApp.MyExtensions.SpecialOne" />
75       </extensions>
76
77       <extensionConfig>
78         <add name="MyExtensionConfigHandler" type="MyApp.MyExtensions.SpecialOne.ConfigHandler" />
79       </extensionConfig>
80     </container>
81   </containers>
82   </unity>
83   <startup>
84     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
85   </startup>
86 </configuration>

 配置过unity的朋友看一下可能就清楚,这边我们再简单说下:

  • Unity的配置节的名称为”Unity",节处理程序的类型为 Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,它包含在程序集Microsoft.Practices.Unity.Configuration 中,当前程序添加该程序集的引用。
  • typeAliases管理生命周期类型,以及一些类型别名的设置,方便我们映射对象的编写,比如同一个类型注册多次,我们只要在typeAlias添加一个类型别名,这样我们再添加这个类型映射的时候只要写个别名就可以了。
  • containers是容器container集合,我们可以配置多个容器类型,通过Name属性就可以访问,比如访问defaultContainer容器代码:configuration.Configure(container, "defaultContainer");
  • container为容器管理,下面包含多个类型映射,我们平常使用的构造器注册、属性注册和方法注册,就可以在constructor、property、method节点进行配置。

资料来源     http://www.cnblogs.com/xishuai/p/3670292.html#xishuai_h8

原文地址:https://www.cnblogs.com/cwmizlp/p/9445316.html

时间: 2024-08-24 16:40:15

C# Unity 依赖注入的相关文章

验证Unity依赖注入的对象是否为同一个实例

在使用Unity的时候,能够很好的解耦,解除层与层之间的依赖性.这里有一个问题,每次向Unity中要对象实例的时候,这时候给出的是同一个吗?还是每次都是new一个新的?我来写代码验证一下.怎么验证两个对象是否为同一个呢,看这个对象在内存中的地址就行了,通过Hash码查看就可以. namespace UnityApplication { public interface IService { string Show(); } } namespace UnityApplication { publi

WPF PRISM开发入门二(Unity依赖注入容器使用)

这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点击这里下载. 运行效果如下: 下面将引入Unity类库,使用Unity来生成需要的对象实例. 先查看一下CalculateRelpLoop类, public class CalculateRelpLoop : ICalculateRelpLoop { ICalculateService _calcu

Unity 依赖注入

关于Ioc的框架有很多,比如astle Windsor.Unity.Spring.NET.StructureMap,我们这边使用微软提供的Unity做示例,你可以使用Nuget添加Unity,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我们就一步一步的学习下Unity依赖注入的详细使用.如果不明白什么是控制反转和依赖注入,请参考控制反转和依赖注入模式 下面通过一个示例来讲解Uni

Unity依赖注入使用详解

Unity依赖注入使用详解 写在前面 构造器注入 Dependency属性注入 InjectionMethod方法注入 非泛型注入 标识键 ContainerControlledLifetimeManager单例 Unity注册配置问题 Unity的app.config节点配置 后记 关于 控制反转 (Inversion of Control)和 依赖注入 (Dependency Injection)大家网上可以找下相关概念,在 <小菜学习设计模式(五)—控制反转(Ioc)> 这篇文章中本人也

使用Unity依赖注入的时候,最上层的类是Resolve还是New的问题

在使用Unity的时候,很多时候是这样一种引用的关系.就是一个类需要另一个类在其中做工具类.因为是构造方法注入,所以要在构造方法中加入一个引用参数. public interface IRepository { void Execute(); } public class Repository : IRepository { public void Execute() { // Some database operation } } public interface IService { voi

使用Microsoft.Practices.Unity 依赖注入

Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入(Constructor Injection).属性注入(Property Injection),以及方法调用注入(Method Call Injection). 假设我们有下面的场景代码,在代码里面有一个很简单的customer对象,customer 对象有个save 方法, 这个方法通过调用ICusto

c# Unity依赖注入WebService

1.IOC与DI简介 IOC全称是Inversion Of Control(控制反转),不是一种技术,只是一种思想,一个重要的面相对象编程的法则,它能知道我们如何设计出松耦合,更优良的程序.传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之 间高耦合,难于测试:有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活.其实IoC 对编程带来的最大改变不是

WebApi学习笔记06:使用webapi模板--仓储模式--Unity依赖注入

1.Web项目 1.1概述 对数据操作封装使用存储模式是很常见的方式,而使用依赖注入来降低耦合度(方便创建对象,可以抛弃经典的工厂模式)…… 1.2创建项目 1.3添加模型 在Models下,添加Product.cs: namespace WebApi06.Models { public class Product { public int ID { get; set; } public string Name { get; set; } public decimal Price { get;

Unity依赖注入

一.简介 Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入.Unity可以处理那些从事基于组件的软件工程的开发人员所面对的问题.构建一个成功应用程序的关键是实现非常松散的耦合设计. 二.使用 1.安装 Unity插件. 进入NuGet,输入Unity.在相应的项目安装. 2.config中代码配置. 在configSections中加入    <section name="unity" type="Microsoft.Practices.U

.NET 用 Unity 依赖注入&mdash;&mdash;注册和解析类型

Unity Unity Application Block (Unity)是一个轻量级的,可扩展的依赖注入容器,它支持构造函数注入,属性注入和方法调用注入.它为开发人员提供了以下优点: 提供简化的对象创建,特别是层级对象结构和依赖,简化应用程序代码: 支持需求抽象:这可以让开发者在运行时或是配置文件指定依赖,简化横切关注点(crosscutting concerns)的管理: 通过延迟组件配置到容器,增加了灵活性: 具有服务定位器功能:这可以让客户存储或缓存容器.对 ASP.NET Web 应用