您现在的位置是:网站首页> 编程资料编程资料
C#使用Unity实现IOC_实用技巧_
2023-05-24
332人已围观
简介 C#使用Unity实现IOC_实用技巧_
一、什么是IOC
学习IOC之前先来了解一个依赖导致原则(DIP),依赖导致原则是IOC的核心原理。
依赖导致:即上层模块不应该依赖于低层模块,二者应该通过抽象来依赖。依赖于抽象,而不是依赖于细节。
首先来看下面的例子:
1、定义一个接口,封装数据库的基本CRUD操作,接口定义如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; namespace DataBase.Interface { /// /// 数据访问接口 /// public interface IDbInterface { string Insert(); string Delete(); string Update(); string Query(); } }2、定义一个MSSQL类实现该接口,用来模仿SQLServer操作,MSSQL类定义如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.MSSQL { public class DbMSSQL : IDbInterface { public string Delete() { return "MSSQL执行删除"; } public string Insert() { return "MSSQL执行插入"; } public string Query() { return "MSSQL执行查询"; } public string Update() { return "MSSQL执行更新"; } } }3、定义一个Oracle类实现该接口,模仿Oracle的操作,Oracle类定义如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.Oracle { public class DbOracle : IDbInterface { public string Delete() { return "Oracle执行删除"; } public string Insert() { return "Oracle执行插入"; } public string Query() { return "Oracle执行查询"; } public string Update() { return "Oracle执行更新"; } } }4、定义一个控制台应用程序来调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DataBase.Interface; using DataBase.MSSQL; namespace IOCConApp { class Program { static void Main(string[] args) { // 常规做法,即程序的上端,依赖于下端,依赖于细节 DbMSSQL mssql = new DbMSSQL(); } } }常规做法是添加引用,然后直接实例化类,但是这样会依赖于细节实现,现将代码修改如下:
// 通过抽象来依赖 IDbInterface dbInterface = new DbMSSQL();
但是这样修改以后,虽然左边是抽象了,但是右边还是依赖于细节。
那就究竟什么是IOC呢?
IOC(Inversion of Control)即控制反转,是一个重要的面向对象编程的法则来消减程序之间的耦合问题,把程序中上层对下层依赖,转移到一个第三方容器中来装配。IOC是程序设计的目标,实现方式包含依赖注入和依赖查找,在.net中只有依赖注入。
说到IOC,就不能不说DI。DI:即依赖注入,是IOC的实现手段。
二、使用Unity实现IOC
Unity是一个IoC容器,用来实现依赖注入(Dependency Injection,DI),减少耦合的,Unity出自于伟大的微软。
unity能够做什么呢,列举部分如下:
1.Unity支持简单对象创建,特别是分层对象结构和依赖,以简化程序代码。其包含一个编译那些可能存在依赖于其他对象的对象实例机制。
2.Unity支持必要的抽象,其允许开发者在运行时或配置去指定依赖关系同时可以简单的管理横切点(AOP)。
3.Unity增加了推迟到容器组件配置的灵活性。其同样支持一个容器层次的结构。
4.Unity拥有服务定位能力,对于一个程序在许多情况下重复使用组件来分离和集中功能是非常有用的。
5.Unity允许客户端储存或缓存容器。对于在ASP.NET Web applications中开发者将容器持久化于ASP.NET中的session或application中特别有效。
6.Unity拥有拦截能力,其允许开发者通过创建并执行handlers(在方法或属性被调用到达之前)来为已存在的组件增加一个函数,并再次为返回调用结果。
7.Unity可以从标准配置系统中读取配置信息,例如:XML文件,同时使用配置文件来配置容器。
8.Unity支持开发者实现自定义容器扩展,例如:你可以实现方法来允许额外的对象构造和容器特征,例如缓存。
9.Unity允许架构师和开发者在现代化的程序中更简单的实现通用设计模式。
什么情况下要使用unity呢?
1.所构建的系统依赖于健全的面向对象原则,但是大量不同的代码交织在一起而难以维护。
2.构建的对象和类需要依赖其他对象或类。
3.依赖于复杂的或需要抽象的对象。
4.希望利用构造函数、方法或属性的调用注入优势。
5.希望管理对象实例的生命周期。
6.希望能够在运行时管理并改变依赖关系。
7.希望在拦截方法或属性调用的时候生成一个策略链或管道处理容器来实现横切(AOP)任务。
8.希望在Web Application中的回发操作时能够缓存或持久化依赖关系。
1、程序中安装Unity
使用管理NuGet程序包来安装Unity,在项目上右键,选择管理NuGet程序包:

在搜索框里面输入Unity,点击右侧安装按钮进行安装:

出现以下信息表示安装成功:

2、使用Unity实现DI
先来看看最简单的Unity实现方式:
IUnityContainer container = new UnityContainer();//1、定义一个空容器 container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例 var db = container.Resolve (); Console.WriteLine(db.Insert()); Console.ReadKey();
结果:

从结果中可以看出,db是DbMSSQL类型的实例。
除了使用RegisterType注册类型以外,还可以注册一个实例,例如:
// 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL() container.RegisterInstance(new DbMSSQL());
3、三种注入方式
三种注入方式:构造函数注入、属性注入、方法注入。
3.1 定义IHeadphone接口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.Interface { public interface IHeadphone { } }3.2 定义IMicrophone接口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.Interface { public interface IMicrophone { } }3.3 定义IPower接口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.Interface { public interface IPower { } }3.4 定义IPhone接口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.Interface { public interface IPhone { void Call(); IMicrophone iMicrophone { get; set; } IHeadphone iHeadphone { get; set; } IPower iPower { get; set; } } }3.5 分别实现上面定义的接口
IPhone接口的实现如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Unity.Attributes; namespace DataBase.MSSQL { public class ApplePhone : IPhone { [Dependency]//属性注入 public IMicrophone iMicrophone { get; set; } public IHeadphone iHeadphone { get; set; } public IPower iPower { get; set; } [InjectionConstructor]//构造函数注入 public ApplePhone(IHeadphone headphone) { this.iHeadphone = headphone; Console.WriteLine("{0}带参数构造函数", this.GetType().Name); } public void Call() { Console.WriteLine("{0}打电话", this.GetType().Name); ; } [InjectionMethod]//方法注入 public void Init1234(IPower power) { this.iPower = power; } } }IHeadphone接口的实现如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.MSSQL { public class Headphone : IHeadphone { public Headphone() { Console.WriteLine("Headphone 被构造"); } } }IMicrophone接口的实现如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.MSSQL { public class Microphone : IMicrophone { public Microphone() { Console.WriteLine("Microphone 被构造"); } } }IPower接口的实现如下:
using DataBase.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBase.MSSQL { public class Power : IPower { public Power() { Console.WriteLine("Power 被构造"); } } }控制台程序调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DataBase.Interface; using DataBase.MSSQL; using Unity; namespace IOCConApp { /// /// IOC():控制反转,把程序上层对下层的依赖,转移到第三方的容器来装配 /// 是程序设计的目标,实现方式包含了依赖注入和依赖查找(.net里面只有依赖注入) /// DI:依赖注入,是IOC的实习方式。 /// class Program { static void Main(string[] args) { #region MyRegion //// 常规做法,即程序的上端,依赖于下端,依赖于细节 //DbMSSQL mssql = new DbMSSQL(); //// 通过抽象来依赖 //IDbInterface dbInterface = new DbMSSQL(); //IUnityContainer container = new UnityContainer();//1、定义一个空容器 //container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例 //var db = container.Resolve(); //// 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL() //container.RegisterInstance(new DbMSSQL()); //Console.WriteLine(db.Insert()); #endregion IUnityContainer container = new UnityContainer(); container.RegisterType(); container.RegisterType(); container.RegisterType(); container.RegisterType(); IPhone phone = container.Resolve(); Console.WriteLine($"phone.iHeadphone==null? {phone.iHeadphone == null}"); Console.WriteLine($"phone.iMicrophone==null? {phone.iMicrophone == null}"); Console.WriteLine($"phone.iPower==null? {phone.iPower == null}"); Console.ReadKey(); } } } 输出结果:

从输出结果中可以看出三种注入方式的执行顺序:先执行构造函数注入,在执行属性注入,最后执行方法注入。
注意:默认情况下如果构造函数上面没有使用特性,那么默认找参数最多的构造函数执行注入。
4、一个接口多个实现进行注册
如果多个不同的实例实现同一个接口,这种情况该怎么注册呢?先来看看下面的代码:
IUnityContainer container = new UnityContainer();//1、定义一个空容器 container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例 container.RegisterType ();//表示遇到IDbInterface的类型,创建DbMSSQL的实例 var db = container.Resolve (); Console.WriteLine(db.Insert());
运行结果:

从运行结果中可以看出,后面注册的类型会把前面注册的类型给覆盖掉,那么该如何解决呢?可以通过参数的方式来解决,代码如下:
IUnityContainer container = new Un
点击排行
本栏推荐
