class unity 定义类_第二十七篇 Unity(IOC)学习详解

本文详细介绍了Unity作为IOC容器的工作原理,包括依赖注入(DI)的概念和重要性。通过实例展示了如何在.NET项目中安装和使用Unity进行DI,包括构造函数注入、属性注入和方法注入。此外,还探讨了Unity的生命周期管理、接口的多种实现注册以及通过配置文件进行容器配置。
摘要由CSDN通过智能技术生成

在介绍如何在程序中使用Unity之前,首先说一下什么是IOC:

IOC是Inversion of Control的缩写,被翻译为控制反转,是一种全新的设计模式,用来削减计算机程序的耦合问题,把程序上层对下层的依赖,转移到第三方的容器来装配。控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。

ca79c393998c0853b67177364d4354d0.png

废话不多说上直接上干货,项目搭建和运行情况

333215c9feecbb7157caa56c74d9c41a.png

2c7c3f714332f3503ca2a5cf7b35b944.png

一.创建项目UnityIOC解决方案二.引入包是4个,其他的文章只引入了3前三个,发现到最后做配置文件管理的时候会报异常,原因是没有引入第四个包,一定要全部引入。

Unity

unity Interception

Unity.Configuration

Unity.Interception.Configuration

6687d0b6c9da5a278670e9ba519f09f1.png

首先来看下面的例子:

1、定义一个接口,封装数据库的基本CRUD操作,接口定义如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Data; 7  8 namespace DataBase.Interface 9 {10     /// 11     /// 数据访问接口12     /// 13    public  interface IDbInterface14     {15         string Insert();16         string Delete();17         string Update();18         string Query();19     }20 }

 2、定义一个MSSQL类实现该接口,用来模仿SQLServer操作,MSSQL类定义如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7  8 namespace DataBase.MSSQL 9 {10     public class DbMSSQL : IDbInterface11     {12         public string Delete()13         {14             return "MSSQL执行删除";15         }16 17         public string Insert()18         {19             return "MSSQL执行插入";20         }21 22         public string Query()23         {24             return "MSSQL执行查询";25         }26 27         public string Update()28         {29             return "MSSQL执行更新";30         }31     }32 }

 3、定义一个Oracle类实现该接口,模仿Oracle的操作,Oracle类定义如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7  8 namespace DataBase.Oracle 9 {10     public class DbOracle : IDbInterface11     {12         public string Delete()13         {14             return "Oracle执行删除";15         }16 17         public string Insert()18         {19             return "Oracle执行插入";20         }21 22         public string Query()23         {24             return "Oracle执行查询";25         }26 27         public string Update()28         {29             return "Oracle执行更新";30         }31     }32 }

 4、定义一个控制台应用程序来调用:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using DataBase.Interface; 7 using DataBase.MSSQL; 8  9 namespace IOCConApp10 {11     class Program12     {13         static void Main(string[] args)14         {15             // 常规做法,即程序的上端,依赖于下端,依赖于细节16             DbMSSQL mssql = new DbMSSQL();17         }18     }19 }

 常规做法是添加引用,然后直接实例化类,但是这样会依赖于细节实现,现将代码修改如下:

1

2

// 通过抽象来依赖

IDbInterface dbInterface = new DbMSSQL();

 但是这样修改以后,虽然左边是抽象了,但是右边还是依赖于细节。

那就究竟什么是IOC呢?

IOC(Inversion of Control)即控制反转,是一个重要的面向对象编程的法则来消减程序之间的耦合问题,把程序中上层对下层依赖,转移到一个第三方容器中来装配。IOC是程序设计的目标,实现方式包含依赖注入和依赖查找,在.net中只有依赖注入。

说到IOC,就不能不说DI。DI:即依赖注入,是IOC的实现手段。

二、使用Unity实现IOC

Unity是一个IoC容器,用来实现依赖注入(Dependency Injection,DI),减少耦合的,Unity出自于伟大的微软。

unity组件网址:http://unity.codeplex.com/

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程序包:

4868c3477de71f89546201aa23de4cce.png

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

a3adc32d2d50a5f71257c23b24f1a6ed.png

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

0222b98b28341424d3fe1722522727b7.png

2、使用Unity实现DI

先来看看最简单的Unity实现方式:

IUnityContainer container = new UnityContainer();//1、定义一个空容器
container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例var db = container.Resolve();
Console.WriteLine(db.Insert());
Console.ReadKey();

 结果:

ad8a8005f404c41c1e3604f5f189068d.png

从结果中可以看出,db是DbMSSQL类型的实例。

除了使用RegisterType注册类型以外,还可以注册一个实例,例如:

// 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL()
container.RegisterInstance(new DbMSSQL());

3、三种注入方式

三种注入方式:构造函数注入、属性注入、方法注入。

3.1 定义IHeadphone接口,代码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace DataBase.Interface 8 { 9     public interface IHeadphone10     {11 12     }13 }

 3.2 定义IMicrophone接口,代码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace DataBase.Interface 8 { 9     public interface IMicrophone10     {11 12     }13 }

 3.3 定义IPower接口,代码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace DataBase.Interface 8 { 9     public interface IPower10     {11 12     }13 }

 3.4 定义IPhone接口,代码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace DataBase.Interface 8 { 9     public interface IPhone10     {11         void Call();12         IMicrophone iMicrophone { get; set; }13         IHeadphone iHeadphone { get; set; }14         IPower iPower { get; set; }15     }16 }

 3.5 分别实现上面定义的接口

IPhone接口的实现如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Unity.Attributes; 8  9 namespace DataBase.MSSQL10 {11     public class ApplePhone : IPhone12     {13         [Dependency]//属性注入14         public IMicrophone iMicrophone { get; set; }15         public IHeadphone iHeadphone { get; set; }16         public IPower iPower { get; set; }17 18         [InjectionConstructor]//构造函数注入19         public ApplePhone(IHeadphone headphone)20         {21             this.iHeadphone = headphone;22             Console.WriteLine("{0}带参数构造函数", this.GetType().Name);23         }24 25         public void Call()26         {27             Console.WriteLine("{0}打电话", this.GetType().Name); ;28         }29 30         [InjectionMethod]//方法注入31         public void Init1234(IPower power)32         {33             this.iPower = power;34         }35     }36 }

a1119924b0c76d4f07d976b0964b98c1.png

 IHeadphone接口的实现如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7  8 namespace DataBase.MSSQL 9 {10     public class Headphone : IHeadphone11     {12         public Headphone()13         {14             Console.WriteLine("Headphone 被构造");15         }16     }17 }

 IMicrophone接口的实现如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7  8 namespace DataBase.MSSQL 9 {10     public class Microphone : IMicrophone11     {12         public Microphone()13         {14             Console.WriteLine("Microphone 被构造");15         }16     }17 }

 IPower接口的实现如下:

 1 using DataBase.Interface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7  8 namespace DataBase.MSSQL 9 {10     public class Power : IPower11     {12         public Power()13         {14             Console.WriteLine("Power 被构造");15         }16     }17 }

 控制台程序调用:

e556e3b469f7a04e0700627b0025f8ff.png

using Microsoft.Practices.Unity.Configuration;

using System;

using System.Collections.Generic;

using System.Configuration;

using System.IO;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using Unity;

using Unity.Lifetime;

using Unity.Interception.Configuration;

using UnityIOC.Interface;

using UnityIOC.MSSQL;

using UnityIOC.Oracle;

namespace UnityIOC

{

    ///

    /// IOC():控制反转,把程序上层对下层的依赖,转移到第三方的容器来装配

    ///          是程序设计的目标,实现方式包含了依赖注入和依赖查找(.net里面只有依赖注入)

    /// DI:依赖注入,是IOC的实习方式。

    /// Unity

    ///unity Interception

    ///Unity.Configuration

    /// Unity.Interception.Configuration

    ///

    class Program

    {

        static void Main(string[] args)

        {

            #region  没有使用依赖注入之前

            string str = string.Empty;

            // 1 常规做法,即程序的上端,依赖于下端,依赖于细节

            DbMSSQL mssql = new DbMSSQL();

            str = mssql.Delete();

            Console.WriteLine(str);

            // 2 通过抽象来依赖

            IDbInterface dbInterface = new DbMSSQL();

            str = dbInterface.Insert();

            Console.WriteLine(str);

            #endregion

            #region 简单使用Unity实现DI

            IUnityContainer container = new UnityContainer();//1、定义一个空容器

            container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例 第一种方式注入

            // 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL() 

            //container.RegisterInstance(new DbMSSQL());//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例 第二种方式注入

            var db = container.Resolve(); // db是DbMSSQL类型的实例

            Console.WriteLine(db.Insert());

            #endregion

            #region 三种注入方式:构造函数注入、属性注入、方法注入

            container = new UnityContainer();//声明一个新的容器

            container.RegisterType();//开启注册,applephone 是 Iphone 的实现类

            container.RegisterType();// 开启注册,Microphone 是 IMicrophone 的实现类

            container.RegisterType();// 开启注册,Headphone 是 IHeadphone 的实现类

            container.RegisterType(); //开启注册,Power 是 IPower 的实现类

            IPhone phone = container.Resolve(); //解决,去实现接口类的方法内容

            phone.Call();

            Console.WriteLine($"phone.iHeadphone==null?  {phone.iHeadphone == null}");

            Console.WriteLine($"phone.iMicrophone==null? {phone.iMicrophone == null}");

            Console.WriteLine($"phone.iPower==null?      {phone.iPower == null}");

            //从输出结果中可以看出三种注入方式的执行顺序:先执行构造函数注入,在执行属性注入,最后执行方法注入。

            //注意:默认情况下如果构造函数上面没有使用特性,那么默认找参数最多的构造函数执行注入。

            #endregion

            #region 一个接口多个实现进行注册

            container = new UnityContainer();//1、定义一个空容器

            container.RegisterType();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例

            container.RegisterType();//表示遇到IDbInterface的类型,创建DbMSSQL的实例

            db = container.Resolve();

            Console.WriteLine(db.Insert());

            //从运行结果中可以看出,后面注册的类型会把前面注册的类型给覆盖掉,那么该如何解决呢?可以通过参数的方式来解决,代码如下

            container = new UnityContainer();//1、定义一个空容器

            container.RegisterType("sql");//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例

            container.RegisterType("oracle");//表示遇到IDbInterface的类型,创建DbMSSQL的实例

            var sql = container.Resolve("sql");

            var oracle = container.Resolve("oracle");

            Console.WriteLine(sql.Insert());

            Console.WriteLine(oracle.Insert());

            #endregion

            #region 生命周期

            container = new UnityContainer();

            container.RegisterType();

            IDbInterface db1 = container.Resolve();

            IDbInterface db2 = container.Resolve();

            Console.WriteLine("HashCode:" + db1.GetHashCode().ToString());

            Console.WriteLine("HashCode:" + db2.GetHashCode().ToString());

            Console.WriteLine(object.ReferenceEquals(db1, db2));

            //表明db1和db2是两个不同的实例,即默认情况下生命周期是瞬时的,每次都是创建一个新的实例。

            //container.RegisterType(new TransientLifetimeManager()); 表示是瞬时生命周期,默认情况下即这种。

            container = new UnityContainer();

            container.RegisterType(new ContainerControlledLifetimeManager());

            IDbInterface db3 = container.Resolve();

            IDbInterface db4 = container.Resolve();

            Console.WriteLine("HashCode:" + db3.GetHashCode().ToString());

            Console.WriteLine("HashCode:" + db4.GetHashCode().ToString());

            Console.WriteLine(object.ReferenceEquals(db3, db4));

            //上图的结果可以看出,db1和db2是同一个实例。

            //container.RegisterType(new ContainerControlledLifetimeManager())表示是容器单例,每次都是同一个实例。

            #endregion

            #region 使用配置文件实现

            //在上面的例子中,所有的例子都是一直在依赖于细节,那么怎么解决不依赖于细节呢?答案是只能使用配置文件,配置文件如下:

            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

            fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "\\unity.config");//找配置文件的路径

            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            container = new UnityContainer();

            section.Configure(container, "testContainer");

            IDbInterface db5 = container.Resolve("sql");

            Console.WriteLine(db.Insert());

            #endregion

            Console.ReadLine();

        }

    }

}

结果:

933b2f28048613906b3b529f195256ad.png

更多技术请关注

06ef13deee2f48d9b0f18c62e21ae8e8.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值