Unity 依赖注入
关于Ioc的框架有很多,比如astle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用Nuget添加Unity,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我们就一步一步的学习下Unity依赖注入的详细使用。如果不明白什么是控制反转和依赖注入,请参考控制反转和依赖注入模式
下面通过一个示例来讲解Unity不同的依赖注入,现在有一家公司,这家公司有很多的员工,这些员工分别来自不同的省份,有的是浙江人,有的是四川人,也有的是湖南人等等,因为公司上了一定的规模,所以为了解决员工的吃饭问题,所以公司决定built一个食堂,但是不同地方的员工的口味不同,所以食堂必须具备烹饪不同菜系的功能,ok,接下来就围绕这这个例子来讲解Unity的依赖注入。
1、构造器注入
IOC容器会智能的选择和调用合适的构造函数,以创建依赖的对象,如果被选择的构造函数具有相应的参数,IOC容器在调用构造函数之前会解析注册的依赖关系并自行获得相应的参数。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity; namespace DependencyInto
{
class Program
{
static void Main(string[] args)
{
UnityContainer contanier = new UnityContainer();
//向IOC容器中注册浙江系菜和四川系菜
contanier.RegisterType<IMess, SiChuanFood>();
contanier.RegisterType<IMess, ZhengJiangFood>(); //IOC容器会智能的选择和调用合适的构造函数,以创建依赖的对象,如果被选择的构造函数具有相应的参数,IOC容器在调用构造函数之前会解析注册的依赖关系并自行获得相应的参数。
//获取可行的参数后,将参数注入到对应的类中
IEmployee employee=contanier.Resolve<SiChuanEmployee>();
IEmployee employees = contanier.Resolve<ZheJiangEmployee>();
employee.EatFood();
employees.EatFood();
Console.ReadLine();
}
}
/// <summary>
/// 员工接口,里面包含员工最基本的权利
/// </summary>
internal interface IEmployee
{
void EatFood();
} /// <summary>
/// 食堂接口,里面包含食堂最基本的用途
/// </summary>
internal interface IMess
{
string GetFood();
} /// <summary>
/// 浙江系菜
/// </summary>
internal class ZhengJiangFood : IMess
{ public string GetFood()
{
return "浙江菜";
}
} /// <summary>
/// 四川系菜
/// </summary>
internal class SiChuanFood : IMess
{ public string GetFood()
{
return "四川菜";
}
} /// <summary>
/// 四川员工
/// </summary>
internal class SiChuanEmployee : IEmployee
{
private IMess _mess; /// <summary>
/// 通过构造函数注入食堂接口实例
/// </summary>
/// <param name="mess">食堂接口实例</param>
public SiChuanEmployee(IMess mess)
{
this._mess = mess;
}
public void EatFood()
{
Console.WriteLine("四川人吃" + _mess.GetFood());
}
} /// <summary>
/// 浙江员工
/// </summary>
internal class ZheJiangEmployee : IEmployee
{
private IMess _mess;
/// <summary>
/// 通过构造函数注入食堂接口实例
/// </summary>
/// <param name="mess">食堂接口实例</param>
public ZheJiangEmployee(IMess mess)
{
this._mess = mess;
}
public void EatFood()
{
Console.WriteLine("浙江人吃"+_mess.GetFood());
}
}
}

UnityContainer的实例方法:RegisterType 向容器中注册需要通过容器生成的对象
UnityContainer的实例方法:Resolve 设置生成的对象的注入目标(就是设置生成的对象需要注入哪个目标)
2、属性注入-通过Dependency特性
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity; namespace DependencyInto
{
class Program
{
static void Main(string[] args)
{
UnityContainer contanier = new UnityContainer();
//向IOC容器中注册浙江系菜和四川系菜
contanier.RegisterType<IMess, SiChuanFood>();
contanier.RegisterType<IMess, ZheJiangFood>(); //IOC容器会智能的选择和调用合适的构造函数,以创建依赖的对象,如果被选择的构造函数具有相应的参数,IOC容器在调用构造函数之前会解析注册的依赖关系并自行获得相应的参数。
//获取可行的参数后,将参数注入到对应的类中
IEmployee employee=contanier.Resolve<SiChuanEmployee>();
IEmployee employees = contanier.Resolve<ZheJiangEmployee>();
employee.EatFood();
employees.EatFood();
Console.ReadLine();
}
}
/// <summary>
/// 员工接口,里面包含员工最基本的权利
/// </summary>
internal interface IEmployee
{
void EatFood();
} /// <summary>
/// 食堂接口,里面包含食堂最基本的用途
/// </summary>
internal interface IMess
{
string GetFood();
} /// <summary>
/// 浙江系菜
/// </summary>
internal class ZheJiangFood : IMess
{ public string GetFood()
{
return "浙江菜";
}
} /// <summary>
/// 四川系菜
/// </summary>
internal class SiChuanFood : IMess
{ public string GetFood()
{
return "四川菜";
}
} /// <summary>
/// 四川员工
/// </summary>
internal class SiChuanEmployee : IEmployee
{ #region 属性注入依赖
private IMess _mess; [Dependency]
public IMess Mess
{
get
{
return this._mess;
}
set
{
this._mess = value;
}
}
#endregion public void EatFood()
{
Console.WriteLine("四川人吃" + Mess.GetFood());
}
} /// <summary>
/// 浙江员工
/// </summary>
internal class ZheJiangEmployee : IEmployee
{ #region 属性注入依赖
private IMess _mess; [Dependency]
public IMess Mess
{
get
{
return this._mess;
}
set
{
this._mess = value;
}
}
#endregion public void EatFood()
{
Console.WriteLine("浙江人吃"+_mess.GetFood());
}
}
}

ok,输出结果一样,通过Dependency特性声明需要外部注入依赖的属性,注:该特性

3、方法注入-通过InjectionMethod特性
方法注入和属性方式使用一样,方法注入只需要在方法前加[InjectionMethod]标记就行了从方法注入的定义上看,只是模糊的说对某个方法注入,但是方法注入无非三种:
a、方法参数注入
b、方法返回值注入
c、方法中的引用注入
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity; namespace DependencyInto
{
class Program
{
static void Main(string[] args)
{
UnityContainer contanier = new UnityContainer();
//向IOC容器中注册浙江系菜和四川系菜
contanier.RegisterType<IMess, SiChuanFood>();
contanier.RegisterType<IMess, ZheJiangFood>(); //IOC容器会智能的选择和调用合适的构造函数,以创建依赖的对象,如果被选择的构造函数具有相应的参数,IOC容器在调用构造函数之前会解析注册的依赖关系并自行获得相应的参数。
//获取可行的参数后,将参数注入到对应的类中
IEmployee employee = contanier.Resolve<SiChuanEmployee>();
ZheJiangEmployee employees = contanier.Resolve<ZheJiangEmployee>();
employee.EatFood();
employees.EatFood();
Console.WriteLine("people.tool == null(引用) ? {0}", employees._mess1== null ? "Yes" : "No");
Console.WriteLine("people.tool2 == null(参数) ? {0}", employees._mess2 == null ? "Yes" : "No");
Console.WriteLine("people.tool3 == null(返回值) ? {0}", employees._mess3 == null ? "Yes" : "No");
Console.ReadLine();
}
}
/// <summary>
/// 员工接口,里面包含员工最基本的权利
/// </summary>
internal interface IEmployee
{
void EatFood();
} /// <summary>
/// 食堂接口,里面包含食堂最基本的用途
/// </summary>
internal interface IMess
{
string GetFood();
} /// <summary>
/// 浙江系菜
/// </summary>
internal class ZheJiangFood : IMess
{ public string GetFood()
{
return "浙江菜";
}
} /// <summary>
/// 四川系菜
/// </summary>
internal class SiChuanFood : IMess
{ public string GetFood()
{
return "四川菜";
}
} /// <summary>
/// 四川员工
/// </summary>
internal class SiChuanEmployee : IEmployee
{ #region 方法注入
public IMess _mess1;//我是对象引用
public IMess _mess2;//我是参数
public IMess _mess3;//我是返回值 /// <summary>
/// 通过方法里面的引用注入
/// </summary>
[InjectionMethod]
public void MethodInto1()
{
if (object.ReferenceEquals(_mess1, null)) { }
} /// <summary>
/// 通过方法参数注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public void MethodInto2(IMess mess)
{
this._mess2 = mess;
} /// <summary>
/// 通过方法返回值注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public IMess MethodInto3()
{
return _mess3;
} #endregion public void EatFood()
{
Console.WriteLine("四川人吃" + _mess2.GetFood());
}
} /// <summary>
/// 浙江员工
/// </summary>
internal class ZheJiangEmployee : IEmployee
{ #region 方法注入
public IMess _mess1;//我是对象引用
public IMess _mess2;//我是参数
public IMess _mess3;//我是返回值 /// <summary>
/// 通过方法里面的引用注入
/// </summary>
[InjectionMethod]
public void MethodInto1()
{
if (object.ReferenceEquals(_mess1, null)) { }
} /// <summary>
/// 通过方法参数注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public void MethodInto2(IMess mess)
{
this._mess2 = mess;
} /// <summary>
/// 通过方法返回值注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public IMess MethodInto3()
{
return _mess3;
} #endregion public void EatFood()
{
Console.WriteLine("浙江人吃" + _mess2.GetFood());
}
}
}
4、配置文件配置IOC
到目前位置三种依赖注入的三种方式,都已近介绍了,但是除了构造器注入当我们使用属性注入和方法注入的时候,并通过RegisterType,会产生代码产生耦合,当我们添加一个方法或者一个属性或者添加一个方法,都需要去修改代码,这中设计显然是不太合理的,所以我们要做的是,不去修改代码而是通过修改配置文件的方式,具体代码如下:
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration> <configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<containers>
<container name="defaultContainer">
<register type="DependencyInto.IMess, DependencyInto" mapTo="DependencyInto.ZheJiangFood, DependencyInto"/>
<register type="DependencyInto.IEmployee,DependencyInto" mapTo="DependencyInto.ZheJiangEmployee,DependencyInto"/>
</container>
</containers>
</unity> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
指定自定义节点名称,和处理自定义节点的一般处理程序
unity配置节点
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration; namespace DependencyInto
{
class Program
{
static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
//UnityConfigurationSection.SectionName="untiy"
//通过GetSection()获得unity自定义节点,并且根据该节点下面的内容生成UnityConfigurationSection实例
UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
configuration.Configure(container, "defaultContainer");//设置容器的名称,并对其进行配置
IEmployee people = container.Resolve<IEmployee>();
people.EatFood();
Console.ReadLine();
}
}
/// <summary>
/// 员工接口,里面包含员工最基本的权利
/// </summary>
internal interface IEmployee
{
void EatFood();
} /// <summary>
/// 食堂接口,里面包含食堂最基本的用途
/// </summary>
internal interface IMess
{
string GetFood();
} /// <summary>
/// 浙江系菜
/// </summary>
internal class ZheJiangFood : IMess
{ public string GetFood()
{
return "浙江菜";
}
} /// <summary>
/// 四川系菜
/// </summary>
internal class SiChuanFood : IMess
{ public string GetFood()
{
return "四川菜";
}
} /// <summary>
/// 四川员工
/// </summary>
internal class SiChuanEmployee : IEmployee
{ #region 方法注入
public IMess _mess1;//我是对象引用
public IMess _mess2;//我是参数
public IMess _mess3;//我是返回值 /// <summary>
/// 通过方法里面的引用注入
/// </summary>
[InjectionMethod]
public void MethodInto1()
{
if (object.ReferenceEquals(_mess1, null)) { }
} /// <summary>
/// 通过方法参数注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public void MethodInto2(IMess mess)
{
this._mess2 = mess;
} /// <summary>
/// 通过方法返回值注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public IMess MethodInto3()
{
return _mess3;
} #endregion public void EatFood()
{
Console.WriteLine("四川人吃" + _mess2.GetFood());
}
} /// <summary>
/// 浙江员工
/// </summary>
internal class ZheJiangEmployee : IEmployee
{ #region 方法注入
public IMess _mess1;//我是对象引用
public IMess _mess2;//我是参数
public IMess _mess3;//我是返回值 /// <summary>
/// 通过方法里面的引用注入
/// </summary>
[InjectionMethod]
public void MethodInto1()
{
if (object.ReferenceEquals(_mess1, null)) { }
} /// <summary>
/// 通过方法参数注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public void MethodInto2(IMess mess)
{
this._mess2 = mess;
} /// <summary>
/// 通过方法返回值注入
/// </summary>
/// <param name="mess"></param>
[InjectionMethod]
public IMess MethodInto3()
{
return _mess3;
} #endregion public void EatFood()
{
Console.WriteLine("浙江人吃" + _mess2.GetFood());
}
}
}
输出:
5、ContainerControlledLifetimeManager单例
如果不清楚单例模式,请参考Sington(单例模式),Unity提供了单例模式,并将单例实例的生命周期叫给了对应的容器管理,代码如下:
UnityContainer container = new UnityContainer();
container.RegisterType<IMess, ZheJiangFood>("aa");
IMess ee = container.Resolve<ZheJiangFood>("aa");
IMess ee1 = container.Resolve<ZheJiangFood>("aa");
Console.WriteLine("same instance?ansmer is {0}", object.ReferenceEquals(ee, ee1));
Console.ReadLine();

修改第二行代码如下:
container.RegisterType<IMess, ZheJiangFood>("aa",new ContainerControlledLifetimeManager());

上面演示了将IMess注册为ZheJiangFood,并声明为单例,ContainerControlledLifetimeManager字面意思上就是Ioc容器管理声明周期,我们也可以不使用类型映射,将某个类注册为单例:
UnityContainer container = new UnityContainer();
ZheJiangFood food = new ZheJiangFood();
container.RegisterInstance<IMess>("aa",food,new ContainerControlledLifetimeManager());
IMess ee = container.Resolve<IMess>("aa");
IMess ee1 = container.Resolve<IMess>("aa");
Console.WriteLine("same instance?ansmer is {0}", object.ReferenceEquals(ee, ee1));
Console.ReadLine();

当我们声明一个类型为ContainerControlledLifetimeManager,说明该类型就是单例,所以当我们在程序中中获取该类型的实例时,IOC容器会返回上次创建的实例,而不会重新创建一个实例,这也是单例的精髓之处,但是具体的实例销毁时间,可能是容器销毁的时候,也可能是应用程序销毁的时候,具体我也不是很清楚.
Unity 依赖注入的更多相关文章
- Unity 依赖注入之二
1. 构造子注入 1.1 构造子注入初级代码 container.RegisterType<IMyWork, MyWork>(new InjectionConstructor(new Bo ...
- Unity依赖注入使用详解
写在前面 构造器注入 Dependency属性注入 InjectionMethod方法注入 非泛型注入 标识键 ContainerControlledLifetimeManager单例 Unity注册 ...
- WPF PRISM开发入门二(Unity依赖注入容器使用)
这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...
- C# Unity依赖注入
简介: 控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的手中,在这个过程中你不是一个控制者而是一个请求者,依赖于容器提供给你的资源,控制权落到了容器 ...
- c# Unity依赖注入WebService
1.IOC与DI简介 IOC全称是Inversion Of Control(控制反转),不是一种技术,只是一种思想,一个重要的面相对象编程的法则,它能知道我们如何设计出松耦合,更优良的程序.传统应用程 ...
- 使用Microsoft.Practices.Unity 依赖注入
Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入 ...
- 使用Microsoft.Practices.Unity 依赖注入 转载https://www.cnblogs.com/slardar1978/p/4205394.html
Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(6)-Unity 依赖注入
系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 本节重构一下代码,采用IOC控制反转,也就是依赖注入 您可以访问http://unity.codeplex.com/rel ...
- Unity 依赖注入知识点
三种依赖注入方法,构造器注入.属性注入.方法注入 可以配置Config文件,来实现不用修改代码.需要先将接口与实体关联,然后使用时会自动加载对应实体. namespace WeChatConsole ...
随机推荐
- HRBUST1200 装修 2017-03-06 15:41 94人阅读 评论(0) 收藏
装修 hero为了能顺利娶princess ,花了血本,买了个房子,现在决定装修.房子的长度为n米,宽度为3米,现在我们有2种地砖,规格分别是1米×1米,2米×2米,如果要为该教室铺设地砖,请问有几种 ...
- B-spline Curves 学习之B样条曲线的移动控制点、修改节点分析(7)
B-spline Curves: Moving Control Points 本博客转自前人的博客的翻译版本,前几章节是原来博主的翻译内容,但是后续章节博主不在提供翻译,后续章节我在完成相关的翻译学习 ...
- 【JAVA 学习笔记1】代码注释
在JAVA中支持单行注释和多行注释 1.单行注释,只要在注释的一行代码中加上双斜杠即可 例如: // int a=2,b=4,c=8; 2.多行注释,在开始位置加上/* 结束位置加上*/ 例如 /* ...
- [Erlang18]教练!又发现Erlang Shell里面的神奇函数一只
人嘛,总是想提高效率,创造更多的价值,同时也得到更多的选择空间.可一个人的精力,时间终归是有限的,减少自身重复或无意义工作就显得格外重要! 要么懂得授权,要么把重复的工作交给机器来做: 现实: 美 ...
- mysqldump的简单使用
背景 需要搞mysql数据同步,从一台服务器把数据库同步到另外一台服务器上,如果折腾过的话,就知道有个这玩意--mysqldump,其实就是mysql自带的一个命令而已 操作步骤 1. 认识mysql ...
- 利用反射(Reflection)处理对象
创建一个学生类: public class Student { public int Id { set; get; } public string Name { set; get; } public ...
- MVC中用jQuery加BootStrap实现动态增加删除文本输入框!
http://www.freejs.net/article_biaodan_278.html 这是在网上找到方法,我修改了一下实合我的项目,发博只为收藏记录并加深记忆. 修改后效果如下 @model ...
- gitlab中修改项目名称客户端修改方法
如果gitlab项目名称已经修改,对于本地已经克隆下来的仓库,可以使用如下命令进行修改: git remote set-url origin 新的项目路径
- “全栈2019”22篇Java异常学习资料及总结
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"22篇Ja ...
- 2017.06.04【NOIP提高组】模拟赛B组:
t1 jzoj3762 过河 路径分段,计算出向上移对答案贡献最大的一段路,再使用堆来维护即可 代码: #include<bits/stdc++.h> using namespace st ...