zoukankan      html  css  js  c++  java
  • IOC注入框架——Unity中的BuildUp与LifetimeManagers

    一、使用BuildUp向已存在的对象进行依赖注入
    准备工作:编写下面的几个类


    public class Owner
    {
        public string Name
        {
            get
            {
                return "Inrie";
            }
        }

        public int Age
        {
            get
            {
                return 24;
            }
        }
    }

    public abstract class Player
    {
        public abstract void Play();

        public abstract string Name { get; }

        [Dependency]
        public Owner Owner { get; set; }
    }

    public class Mp3Player : Player
    {
        public override void Play()
        {
            Console.WriteLine("Playing Mp3");
        }

        public override string Name
        {
            get
            {
                return "Mp3 Player";
            }
        }
    }

    public class CDPlayer : Player
    {
        public override void Play()
        {
            Console.WriteLine("Playing CD");
        }

        public override string Name
        {
            get
            {
                return "CD Player";
            }
        }
    }

    public class DVDPlayer : Player
    {
        public override void Play()
        {
            Console.WriteLine("Playing DVD");
        }

        public override string Name
        {
            get
            {
                return "DVD Player";
            }
        }
    }
    public class TempBuildUp
    {
    public TempBuildUp()
    {
    }
    }
    public class CoreLib
    {
        public Player CreatePlayer()
        {
            return new Mp3Player();
        }
    }

    按照我们上篇文章说的依赖注入,我们看到在MP3Player这个类中的Name属性依赖于Owner类,因此在编写代码的时候我们需要使用UnityContainer进行依赖注入。
    如:
        IUnityContainer container = new UnityContainer();
        container.RegisterType<Player, Mp3Player>();
        Player player = container.Resolve<Player>();
        Response.Write(player.Owner.Name);
       
    但是如果我把代码改为如下方式:
        Player player = new Mp3Player();
        Response.Write(player.Owner.Name);
    代码会抛出异常("未将对象引用设置到对象实例"),这是什么原因呢?
    因为,我们没有使用UnityContainer容器实例化Player,如果目标对象并非由容器实例化(非 Resolve 创建),那么依赖注入行为是不会发生的。(车延禄)

    除了使用UnitContainer对象的Resolve方法实例化对象,我们还可以使用BuildUp进行操作,BuildUp就是对已存在的对象进行依赖注入。
    如:
        IUnityContainer container = new UnityContainer();
        Player player = new Mp3Player();    //未实现依赖的Player对象
        Player p = container.BuildUp<Player>(player);   //对player对象进行依赖注入
        Response.Write(p.Owner.Name);   //执行成功。
       
    下面再看一个例子:
    通过CoreLib类来创建Player对象,然后显示该Player对象的Owner.Name属性。
    现在出现了一个新的问题:Player对象的创建过程在Corelib的CreatePlayer方法中执行的,该方法只是简单地生成MP3Player对象,并没有对它进行依赖注入,即意味着,CoreLib.CreatePlayer()生成的Player对象的Owner引用是Null。
    所以如果客户码这样编写就错了:
        CoreLib lib = new CoreLib();
        Player player = lib.CreatePlayer();
        Response.Write(player.Owner.Name);
    聪明的朋友一眼能看出来,这里没有使用依赖注入。但由于Player对象的生成在CoreLib中实现,并不在我们客户代码的控制范围之内,因此我们无法使用Resolve在客户代码中通过CoreLib对象创建Player对象实例。
    在这种情况下,我们可以使用Container的BuildUp()方法,在CoreLib对象中动态进行依赖注入。
    代码如下:
        IUnityContainer container = new UnityContainer();
        CoreLib lib = new CoreLib();    //生成CoreLib对象
        Player p = lib.CreatePlayer(); //通过CoreLib对象生成Player对象,但此时p还是个“半成品”
        Player player = container.BuildUp<Player>(p);   //对“半成品”p进行依赖注入
        Response.Write(player.Owner.Name); //执行成功
       
    二、Lifetime Managers 管理对象的生命周期
    Lifetime Managers控制怎样存放到对象实例的引用和容器怎样销毁这些实例,也就是说Unity基于具体的Lifetime Manager 类去管理对象的创建和销毁。
    目前Unity中提供两个Lifetime Manager类可供我们直接使用,当然你也可以实现自己的Lifetime Manager类。
    A. ContainerControlledLifetimeManager
    Unity保存一个指向对象实例的引用。通过Unity容器为同一个类型或对象获取对象实例时,每次获取到的都是同一个实例。也就是说实现了对象单例模式。默认情况下,RegisterInstance方法使用该Lifetime Manager。

    B. ExternallyControlledLifetimeManager
    Unity仅保存一个指向对象实例的弱引用。通过Unity容器为同一个类型或对象获取对象实例时,每次获取到的都是同一个实例,也是单例模式。但是由于当对象创建完之后,容器没有对该对象的强引用,所以就可能出现当其他地方没有去强引用它时候,会被GC回收掉。

    1.RegisterType
    当用RegisterType注册映射关系时,如果没有指定LifetimeManager,默认是使用一个瞬态的Lifetime Manager。即每次通过Unity容器获取对象的实例时都会重新创建一个该实例,也就是说Unity容器不存在一个到该对象的引用。
    如:
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IPlayer, Mp3Player>();

    IPlayer player1 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player1 HashCode: {0}",player1.GetHashCode()));

    IPlayer player2 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player2 HashCode: {0}",player2.GetHashCode()));
    代码执行结果:


    通过输出的player1和player2对象的HashCode值可以看出,player1和player2分别是Mp3Player类的不同实例。
    要实现单例模式,通过在RegisterType时为它指定相应的Lifetime Manager可以实现单例模式,从上面对ContainerControlledLifetimeManager和ExternallyControlledLifetimeManager的介绍可以知道,这两个Lifetime Manager都可以支持单例模式。
    如:
    IUnityContainer container = new UnityContainer();
    //这里指定使用ContainerControlledLifetimeManager对象
    container.RegisterType<IPlayer, Mp3Player>(new ContainerControlledLifetimeManager());

    IPlayer player1 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player1 HashCode: {0}",player1.GetHashCode()));

    IPlayer player2 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player2 HashCode: {0}",player2.GetHashCode()));
    执行结果


    通过输出结果可以看出,player1和player2对象为Mp3Player类的同一实例,指向同一内存地址。

    2. RegisterInstance
    当用RegisterInstance注册映射关系时,如果没有指定Lifetime Manager,默认是使用ContainerControlledLifetimeManager,即支持单例模式。
    如:(车延禄)
    IUnityContainer container = new UnityContainer();
    IPlayer mp3Player = new Mp3Player();
    container.RegisterInstance<IPlayer>(mp3Player);

    IPlayer player1 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player1 HashCode: {0}", player1.GetHashCode()));

    IPlayer player2 = container.Resolve<IPlayer>();
    Console.WriteLine(string.Format("Player2 HashCode: {0}", player2.GetHashCode()));
    代码执行结:


    通过输出结果可以看出,player1和player2对象为Mp3Player类的同一实例,指向同一内存地址。

  • 相关阅读:
    readonly const
    多线程的安全性
    【C++】operator运算符重载
    C++ 多态的实现及原理(转载)
    C语言宽字符处理函数对照表
    UTF8编码规则(转)
    PE文件结构(转)
    C语言中宏定义
    汇编语言移位指令
    数组指针应该结合二维数组多维数组来理解
  • 原文地址:https://www.cnblogs.com/zpc870921/p/2742981.html
Copyright © 2011-2022 走看看