一、前言

Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入。在Nuget里安装unity

二、Unity的API方法

UnityContainer.RegisterType<ITFrom,TTO>();  //注册映射

UnityContainer.RegisterType< ITFrom, TTO >("keyName");//注册映射指定key值

IEnumerable<T> databases = UnityContainer.ResolveAll<T>(); //返回所有注册同一个接口的实例对象

IT instance = UnityContainer.Resolve<IT>();  //返回最后一个注册同一个接口的实例对象,每次都是创建新的对象

T instance = UnityContainer.Resolve<T>("keyName");//根据key值获取指定的实例对象,每次都是创建新的对象

UnitContainer.RegisterInstance<T>("keyName",new T()); //单例模式,指定key值,获取同一个实例对象

UnityContainer.BuildUp(existingInstance);

IUnityContainer childContainer1 = parentContainer.CreateChildContainer();

三、示例代码

1.演示的是container.Resolve<T>()创建T类型,而T是否已经注册过了,没注册过的就会尝试去创建T类型,在创建T类型的构造函数时,如果需要传递参数,也要涉及到参数是否注册过的问题

定义日志接口

  public interface ILogger
    {
        void Write(string log);
    }

 public class FileLogger:ILogger
    {
        public void Write(string log)
        {
            Console.WriteLine("输出日志到文件!");
        }

    }

  public class ConsoleLogger : ILogger
    {

       public void Write(string log)
       {
           Console.WriteLine("输出日志到控制台!");
       }
    }

定义数据库类

  public class Database
    {
    }

 public class CustomerDatabase : Database
    {
        private ILogger _logger;

        public CustomerDatabase(ILogger logger)
        {
            _logger = logger;
        }
         public void Write(string log)        {            _logger.Write(log);        }
    }
   static void Main(string[] args)
        {

            //实例化Unity容器
            UnityContainer container = new UnityContainer();
            //注册类型映射
            container.RegisterType<ILogger, FileLogger>();
            container.RegisterType<ILogger, ConsoleLogger>();
            //使用Resolve方法创建我们定义好的CustomerDatabase类型,如果在容器中没有注册的类型。执行Resolv方法后,Unity尝试创建该类型,会执行该类的构造器
            //  public CustomerDatabase(ILogger logger)的构造函数需要传递一个日志接口实例,它默认传递上面最后注册的ConsoleLogger实例
            CustomerDatabase database = container.Resolve<CustomerDatabase>();
            database.Write("qqq");
            Console.ReadKey();
        }

2.演示的是创建注册过的实例,并且返回的是新对象

 static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<ILogger, FileLogger>();
            ILogger logger = container.Resolve<ILogger>();
            ILogger logger2 = container.Resolve<ILogger>();
            Console.WriteLine(object.ReferenceEquals(logger,logger2));
            Console.ReadKey();

        }

输出的是false,是不同的对象,说明每次调用container.Resolve<ILogger>()返回的是新的FileLogger对象

3.演示的是每次返回的都是同一个对象,不要例如2创建不同的对象,就像单例模式,RegisterType方法包含一个重载,将使用 new ContainerControlledLifetimeManager()

 static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<ILogger, FileLogger>();
            container.RegisterType<Database, CustomerDatabase> (new ContainerControlledLifetimeManager());
            CustomerDatabase bs1 = container.Resolve<CustomerDatabase>();
            CustomerDatabase bs2 = container.Resolve<CustomerDatabase>();
            Console.WriteLine(object.ReferenceEquals(bs1, bs2));
            Console.ReadKey();

        }

4.如果类似例子1,注册同一个接口的不同实例 ,使用 container.Resolve<ILogger>();只是返回最后一个注册的ConsoleLogger实例,改进在我们向容器里注册时,可以附带一个string 类型的Key值。可以使用key值获取指定的实例对象

            //注册类型映射,同一个接口的不同实例
            container.RegisterType<ILogger, FileLogger>();
            container.RegisterType<ILogger, ConsoleLogger>();            使用 container.Resolve<ILogger>();只是返回最后一个注册的ConsoleLogger实例            ILogger logger2 = container.Resolve<ILogger>();改进如下:再创建两个数据库类
  public class SQLDatabase:Database
    {
    }
 public class ORACLEDatabase:Database
    {
    }

使用key获取指定的数据库实例对象

  static void Main(string[] args)
        {

            UnityContainer container = new UnityContainer();
            container.RegisterType<Database, SQLDatabase>("SQL");
            container.RegisterType<Database, ORACLEDatabase>("ORACLE");
            //返回所有的实例
            IEnumerable<Database> databases = container.ResolveAll<Database>();
            //根据key返回指定的SQL数据库实例
            Database database = container.Resolve<Database>("SQL");

        }

5.使用RegisterInstance注册传入的实例,后面再调用Resolve就会像例子3一样返回同一个实例对象

   static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterInstance<Database>(new SQLDatabase());
            container.RegisterInstance<Database>("Oracle", new ORACLEDatabase());
            Database database1 = container.Resolve<Database>();
            Database database2 = container.Resolve<Database>();
            Database oracleDatabase = container.Resolve<Database>("Oracle");
            Console.WriteLine(object.ReferenceEquals(database1, database2));
            Console.ReadKey();
        }

5.1我们还有一种方法可以把已经存在的实例注入到容器中,这里用到了BuildUp和RegisterInstance,其实我觉得用不用BuildUp都可以了

  public class DB2Database:Database
    {
        [Dependency]
        public ILogger Logger { get; set; }
    }
 static void Main(string[] args)
        {
  UnityContainer container = new UnityContainer();
            container.RegisterType<ILogger, FileLogger>();
            DB2Database existDatabase = new DB2Database();
            container.BuildUp(existDatabase);
            container.RegisterInstance<Database>(existDatabase);
            //DB2Database的属性中Logger上面打了 [Dependency]特性,所以根据这里RegisterType<ILogger, FileLogger>();会默认给DB2Database的Logger属性注入FileLogger
            Database database1 = container.Resolve<Database>();
            Database database2 = container.Resolve<Database>();
            Console.WriteLine(object.ReferenceEquals(database1, database2));
            Console.ReadKey();
}

四、使用配置文件来实现关系映射

1.配置如下

<configuration>
  <configSections>
    <section name="unity"
             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
               Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <container name="containerOne">
      <types>
        <type type="UnityDemo.ILogger" mapTo="UnityDemo.FileLogger"
              lifeTime="Singleton"/>
      </types>

    </container>

  </unity>
</configuration>

2.读取配置文件

第一种,我们使用configurationManager,引用命名空间System.Configuration

           IUnityContainer myContainer = new UnityContainer();

            myContainer.LoadConfiguration("containerOne ");
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Configure(myContainer, "containerOne");

第二种,我们可以直接用容器读取配置信息

IUnityContainer myContainer = new UnityContainer();

myContainer.LoadConfiguration("containerOne");

通过 Injection API 指定依赖

public class GenericDatabase:Database
    {
        private string _connectionString;
        public ILogger Logger { get; set; }

        public GenericDatabase(string connectionString)
        {
            _connectionString = connectionString;
        }
    }

通过Injection API 来为这个类注入connectionString 和 Logger,首先我们要注册映射关系:

            IUnityContainer container = new UnityContainer();
            container.RegisterType<ILogger, FileLogger>();
            container.RegisterType<Database, GenericDatabase>();

然后通过Injection API 为GenericDatabase注入ConnectionStrings和Logger

container.Configure<InjectedMembers>()
                .ConfigureInjectionFor<GenericDatabase>(
                new InjectionConstructor(
                    ConfigurationManager.ConnectionStrings["ConnectionStrings"] == null
                    ? "defaultConnectionString" : ConfigurationManager.ConnectionStrings["ConnectionStrings"].ConnectionString),
                    new InjectionProperty("Logger")
            );
            Database database = container.Resolve<Database>();

这样最后获得的database 就包含了connection 和 Logger

嵌套式容器

容器是可以嵌套的,获取实例时遵循的规则是,如果子容器里不包含需要的对象,则会去父容器获取。如果有,则从自己里获取。一旦父容器销毁,子容器也随之销毁。

            UnityContainer parentContainer = new UnityContainer();
            IUnityContainer childContainer1 = parentContainer.CreateChildContainer();
            IUnityContainer childContainer2 = parentContainer.CreateChildContainer();
            parentContainer.RegisterType<ILogger, FileLogger>(new ContainerControlledLifetimeManager());
            childContainer1.RegisterType<ILogger, ConsoleLogger>(new ContainerControlledLifetimeManager());
            //子容器childContainer2里面没有注册日志类型,所以从父parentContainer得到FileLogger
            ILogger logger = childContainer2.Resolve<ILogger>();
            logger.Write("qqq");
            //子容器childContainer1里面有注册控制台日志,所以从自己本身得到consoleLogger
            ILogger logger2 = childContainer1.Resolve<ILogger>();

 

Unity轻量级依赖注入容器的更多相关文章

  1. IoC 依赖注入容器 Unity

    原文:IoC 依赖注入容器 Unity IoC 是什么? 在软件工程领域,“控制反转(Inversion of Control,缩写为IoC)”是一种编程技术,表述在面向对象编程中,可描述为在编译时静 ...

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

    这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...

  3. 不用Unity库,自己实现.NET轻量级依赖注入

    在面向对象的设计中,依赖注入(IoC)作为一种重要的设计模式,主要用于削减计算机程序的耦合问题,相对于Java中的Spring框架来说,微软企业库中的Unity框架是目前.NET平台中运用比较广泛的依 ...

  4. Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

  5. .NET 使用unity实现依赖注入

    原文地址:http://www.cnblogs.com/wujy/p/3317795.html 一:理论部分 依赖注入:这是 Ioc 模式的一种特殊情况,是一种基于改变对象的行为而不改变类的内部的接口 ...

  6. 运用Unity实现依赖注入[结合简单三层实例]

    运用Unity实现依赖注入[结合简单三层实例] 一:理论部分 依赖注入:这是 Ioc 模式的一种特殊情况,是一种基于改变对象的行为而不改变类的内部的接口编程技术.开发人员编写实现接口的类代码,并基于接 ...

  7. 【ASP.Net MVC3 】使用Unity 实现依赖注入

    转载于:http://www.cnblogs.com/techborther/archive/2012/01/06/2313498.html 家人身体不太好,好几天没在园子里发帖了. 新项目还是要用M ...

  8. Autofac依赖注入容器

    依赖注入容器-- Autofac https://github.com/danielpalme/IocPerformance Unity 更新频率高,微软的项目Grace 综合性能更高 目录: 一.简 ...

  9. 在 mvc 4 中使用 unity 进行依赖注入

    在 mvc 4 中使用 unity 进行依赖注入 关于依赖注入的概念,这里就不再叙述了,我们用 mvc 4 结合 unity,使用构造函数来进行依 赖注入.具体步骤如下: 1. 首先建立 一个 mvc ...

随机推荐

  1. iOS横竖屏

    现在开发的APP大部分界面是竖屏的,只有视频播放的界面和webview阅读文字的界面是可以横屏操作的. 那么就进行如下处理: 1.首先确保APP支持横屏旋转 2.我的App里面都是走UINavigat ...

  2. Array.prototype.sort()

    sort() 方法对数组的元素做原地的排序,并返回这个数组.默认按照字符串的Unicode码位点(code point)排序. 语法 arr.sort([compareFunction]) 参数 co ...

  3. C/C++:Unions 联合

    原文:http://msdn.microsoft.com/en-us/library/5dxy4b7b(v=vs.80).aspx 联合是用户定义的数据或类类型,在任何时间里,它只包含成员列表中的一个 ...

  4. android之保存偏好设置信息到shareSharedPreferences,轻量级的保存数据的方法

    android之保存偏好设置信息到shareSharedPreferences,轻量级的保存数据的方法   SharedPreferences保存数据到xml文件 有时候要保存activity的某些状 ...

  5. js中数组的检测方法

    在js中可以使用Object.prototype.toString.call()的来检测一个对象是否为一个数组 //检测数组 var a = [1, 2]; console.log(typeof a) ...

  6. win32下用VC扩展PHP全过程

    闲着无聊,打算开发一些PHP组件来玩玩,由于在家没有工作环境,遂打算在win32(我的环境是vista)用VC开发DLL模块,费话不 多说了,进入正题: 一.已经在机器上安装PHP环境的就略过,否则先 ...

  7. 利用Azure高级存储搭建高性能Linux服务器(2)

    我们首先来测试随机写的IOPS,可以看到随机写的IOPS可以达到,顺序写的IOPS可以达到: $ sudo fio -filename=/data/testfile -direct=1 -iodept ...

  8. stm32通用定时器中断问题

    在使用stm32的通用定时器定时中断的时候,发现定时器在完成初始化配置后,定时器UIF位会立刻置位,导致在使能中断后,程序会立刻进入定时器中断. 如果设计代码时不希望定时器配置完成后,立刻进入中断,可 ...

  9. js各种进制数之间的转换

    计算机中常用的进制数有二进制.八进制.十进制.十六进制 一.十进制 to 其他 var x = 10; // 或定义其他值均可 x.toString(n); // n 代表要转换到的进制,比如n可以为 ...

  10. C51变量的存储

    一.全局变量和局部变量 全局变量和局部变量的区别在于作用域的不同.此外还有静态全局变量和静态局部变量. 全局变量作用域为全局,在一个源文件中定义,其他的源文件也可以应用.在其他的源文件中使用exter ...