欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IOC容器:Unity

程序员文章站 2022-07-12 13:03:20
...

IOC简介:

什么是IOC

学习IOC之前先来了解一个依赖倒置原则(DIP),依赖倒置原则是IOC的核心原理。

依赖导致:即上层模块不应该依赖于低层模块,二者应该通过抽象来依赖。依赖于抽象,而不是依赖于细节。

IOC(Inversion of Control), 控制反转

DI (Dependency Injection),依赖注入

IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。

那就究竟什么是IOC呢?

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

说到IOC,就不能不说DI。

DI:即依赖注入,是IOC的实现手段。

有以下优点:

  • 1.简化了对象的创建,特别是针对分层对象结构和依赖关系;
  • 2.需求的抽象,允许开发人员在运行时或配置文件中指定依赖关系,简化横切关注点的管理;
  • 3.推迟为容器配置组件的时机,增加了灵活性;
  • 4.服务定位能力,这使客户能够存储或缓存容器;
  • 5.实例和类型拦截
     

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中的回发操作时能够缓存或持久化依赖关系。

注意

先执行构造函数注入,在执行属性注入,最后执行方法注入。

注意:这个一个单独的配置文件,要把属性里面的复制到输出目录改为始终复制,那么这个配置文件才会生成到Debug目录里面。

如果改成使用配置文件的方式实现的话,代码里面就不会依赖于细节了,只要一个接口类型。既然没有细节了,那么对项目进行如下的改造:把引用里面对细节的引用都去掉,然后Debug文件夹里面没有这两个DLL了,但是这时需要把这两个DLL复制到Debug目录下面,否则程序运行的时候会找不到具体实现的类型。这样就意味着程序架构只依赖于接口。

引用里面只要对接口的引用了,没有对具体实现的引用。去掉了对细节的依赖。

注意:使用配置文件实现时,必须把接口的具体实现类复制到程序目录下面。

如果有额外添加了一种数据库,那么只需要修改配置文件,把新的实现类复制到程序目录下面即可实现程序的升级。

简单例子:

 

    public interface IA { }
    public interface IB { }
    public interface IC { }
    public interface ID { }

    public class A : IA
    {
        public IB B { get; set; }
        [Dependency]
        public IC C { get; set; }
        public ID D { get; set; }

        public A(IB b)
        {
            this.B = b;
            Console.WriteLine("A");
        }
        [InjectionMethod]
        public void Initialize(ID d)
        {
            this.D = d;
        }
    }
    public class AA : IA
    {
        public IB B { get; set; }
        [Dependency]
        public IC C { get; set; }
        public ID D { get; set; }

        public AA(IB b)
        {
            this.B = b;
            Console.WriteLine("AA");
        }
        [InjectionMethod]
        public void Initialize(ID d)
        {
            this.D = d;
        }
    }
    public class B : IB { }
    public class C : IC { }
    public class D : ID { }

代码方式注册:

        static void Main(string[] args)
        { 
            string configFile = "Unity.config";
            var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile }; 
            //从config文件中读取配置信息
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            //获取指定名称的配置节
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
            IUnityContainer container = new UnityContainer();
            section.Configure(container);
            A a = (A)container.Resolve<IA>("A");
            AA aa = (AA)container.Resolve<IA>("AA");

            Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
            Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
            Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");

            Console.Read();
        }

 

配置文件方式注册:

        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer(); //注册映射   
            container.RegisterType<IA, A>();
            container.RegisterType<IB, B>();
            container.RegisterType<IC, C>();
            container.RegisterType<ID, D>();

            //得到A的实例  
            A a = (A)container.Resolve<IA>();

            Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
            Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
            Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");

            Console.Read();
        }

配置文件内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration" />
  </configSections>
  <unity>
    <containers>
      <container>
        <!--逗号前面是接口类型的完全限定名:命名空间+接口名称,逗号后面是DLL文件的名称 name解决同一个接口不同实例问题-->
        <register type="ConsoleApplicationMain.IA, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.A, ConsoleApplicationMain" name="A"/>
        <register type="ConsoleApplicationMain.IA, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.AA, ConsoleApplicationMain" name="AA"/>
        <register type="ConsoleApplicationMain.IB, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.B, ConsoleApplicationMain"/>
        <register type="ConsoleApplicationMain.IC, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.C, ConsoleApplicationMain"/>
        <register type="ConsoleApplicationMain.ID, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.D, ConsoleApplicationMain"/>
      </container>
    </containers>
  </unity>
</configuration>
<!-- 注意:这个一个单独的配置文件,要把属性里面的复制到输出目录改为始终复制,那么这个配置文件才会生成到Debug目录里面。-->

 

参考资料:

IOC容器:Unity
https://www.cnblogs.com/dotnet261010/p/9054201.html
Unity Ioc框架简单例子
https://www.cnblogs.com/dragon-L/p/5124872.html
.NET Unity IOC框架使用实例
https://www.cnblogs.com/pengdylan/p/6371724.html?utm_source=itdadao&utm_medium=referral
依赖注入的三种实现
https://www.cnblogs.com/sylone/p/9479276.html

Demo:

我做了两个demo,一个是简单demo,一个是完整demo;

下载地址:下载源码

 

IOC容器:Unity
1标题
IOC容器:Unity
2标题