Unity

Unity是一个轻量级的,可扩展的依赖项注入容器。

Unity的使用

Unity入门还是比较简单的。不像Java的Spring一样需要大量配置。那么我们马上开始学习如何使用吧。
Unity其实就是一个管理对象的容器,因此使用它的步骤有三
一、初始化容器
二、添加对象到容器
三、从容器中取出对象
看起来很简单对不对,我们首先从一个较简单的实例项目开始。

一、项目构建

1.创建一个控制台程序
2.添加Unity的引用
在这里插入图片描述
我们选上图中第一个。这里我们选择的版本是:5.8.11
在这里插入图片描述

3.接口

public interface IFood
{
    string Name { set; get; }
}

4、实现类

public class Banana:IFood
{
    public string Name { get; set; } = string.Empty;
}
 public class Apple:IFood
{
    public string Name { get; set; } = string.Empty;
}
public class Beef:IFood
{
    public string Name { get; set; } = string.Empty;
}
二、容器的构建

既然是程序来管理对象的使用,那么首先当然要有一个容器来管理对象的创建,以及对象的保存。这样才可以在需要的时刻选择出需要的对象。

public static UnityContainer Container = new UnityContainer();

关于一些初期化的配置我们稍后再了解。先用一个简单的例子学习如何使用。

三、实例的注册
1、RegisterInstance()方法

RegisterInstance()方法有多个扩展。

1)RegisterInstance(object instance)

说明 :向容器中传入一个对象。之后可以根据该对象的声明类型来获取这个对象。

2)RegisterInstance(Type t, object instance)
或者把类型写进泛型里:RegisterInstance<TInterface>(TInterface instance)

说明 :向容器中传入对象,以及一个类型,之后可以根据这个类型来找到这个对象。

3)RegisterInstance(Type t, string name, object instance)
或者把类型写进泛型里:RegisterInstance<TInterface>(string name, TInterface instance)

说明 :向容器传入对象,类型,以及一个字符串(该对象的名字-key)。

上面两种注册方式有一个弊端,一个类型只能保存一个对象,重复传入一个类型的对象时会覆盖上一个对象。而使用类型加名字的方式就可以准确的在同一个类型中根据名字来找到对应的不同对象。但同一个名字依旧只保存一个对象。

4)RegisterInstance(Type type,string name, object instance,LifetimeManager lifetime)
或者把类型写进泛型里:RegisterInstance<TInterface>(string name, TInterface instance,LifetimeManager lifetime)

说明 :向容器中传入对象,类型,字符串,以及该对象的生命周期。使用该扩展来设置该对象的生命周期。通俗的说就是,传入的对象可以在容器中保存多久,时间一过该对象就会被销毁。

Unity内置了6种生存期管理模型
TransientLifetimeManager为每次请求生成新的类型对象实例。
使用该参数时,每次获取的实例都是全新的。
ContainerControlledLifetimeManager每次请求都是开始注册的实例(单例模式)
使用该参数时可以实现单例模式。每次获取的实例都是相同的。
其他请阅读Unity容器中的对象生存期管理等其他文章,这里不做展开。

2、RegisterType()方法

使用RegisterType()方法则表示根据类型自动创建对象,你可以进行一些配置来决定如何创建对象,没有配置的话就会根据构造函数自动帮你new一个(默认使用参数最多的构造函数)。

1)RegisterType(Type type)
或者把类型写进泛型里RegisterType<T>()

说明 :根据类型自动注册一个对象。

2)RegisterType(Type type,string name)
或者把类型写进泛型里:RegisterType<T>(string name)

说明 :根据类型自动注册一个对象,并设置该对象的名字。

3)RegisterType(Type type,string name,LifetimeManager lifetime)
或者把类型写进泛型里:RegisterType<T>(string name,LifetimeManager lifetime)

说明 :根据类型自动注册一个对象,并设置该对象的名字和生命周期。

使用RegisterType()方法注册对象时需要注意,默认生命周期是TransientLifetimeManager每次获得的都是一个全新对象。

四、实例的获取
1.Resolve()方法

1)Resolve(Type type)
或者把类型写进泛型里:Resolve<T>()

说明 :根据类型从容器中取得一个对象。

2)Resolve(Type type,string name)
或者把类型写进泛型里:Resolve<T>(string name)

说明 :根据类型和名字从容器中取得一个对象。

五、程序演示
class Program
{
    public static IUnityContainer Container = new UnityContainer();
    public static void Main(string[] args)
    {
        //声明类型是IFood,真实类型是Apple
        IFood apple = new Apple
        {
            Name = "苹果"
        };
        Banana banana = new Banana
        {
            Name = "香蕉"
        };
        Beef beef = new Beef()
        {
            Name = "牛肉"
        };

        //将apple对象注册到容器
        Container.RegisterInstance(apple);

        //使用Apple类型获取对象
        //这种写法返回一个object类型
        var result = Container.Resolve(typeof(Apple));
        if (result is Apple apple2)
        {
            Console.WriteLine("Apple:" + apple2.Name);
        }

        //使用IFood类型获取对象
        //使用泛型可以直接用泛型类接收。  
        IFood food = Container.Resolve<IFood>();
        Console.WriteLine("IFood:" + food?.Name);

        //将banana对象注册到容器,类型为IFood,此时覆盖之前注册的apple对象,因为类型相同
        Container.RegisterInstance<IFood>(banana);
        //将banana对象注册到容器,类型为IFood,名字叫banana
        Container.RegisterInstance<IFood>("banana", banana);
        //将beef对象注册到容器,类型为IFood,名字叫beef,生命周期设置为每次获取都创建一个全新对象
        Container.RegisterInstance<IFood>("beef", beef, new TransientLifetimeManager());

        food = Container.Resolve<IFood>();
        //因为banana覆盖了apple对象,此时结果应该是:香蕉
        Console.WriteLine("IFood:" + food?.Name);

        food = Container.Resolve<IFood>("banana");
        //使用banana获取对象,结果应该是:香蕉
        Console.WriteLine("banana:" + food?.Name);

        //beef生命周期为马上销毁,每次创建新对象,结果应该是空白
        food = Container.Resolve<IFood>("beef");
        Console.WriteLine("beef:" + food?.Name);

        //自动注册一个Apple对象
        Container.RegisterType<Apple>();
        //自动注册一个Banana对象,生命周期默认是创建全新实例
        Container.RegisterType<Banana>("banana2");
        //自动注册一个Banana对象,该对象是单例的,会一直存在于容器中。
        Container.RegisterType<Banana>("banana3", new ContainerControlledLifetimeManager());

        Apple apple3 = Container.Resolve<Apple>();
        Console.WriteLine("Apple:" + apple3?.Name);

        Banana banana2 = Container.Resolve<Banana>("banana2");
        Console.WriteLine("banana2:" + banana2?.Name);
        if (banana2 != null)
        {
            banana2.Name = "香蕉2";
        }
        banana2 = Container.Resolve<Banana>("banana3");
        Console.WriteLine("banana2:" + banana2?.Name);

        Banana banana3 = Container.Resolve<Banana>("banana3");
        Console.WriteLine("banana3:" + banana3?.Name);
        if (banana3 != null)
        {
            banana3.Name = "香蕉3";
        }
        banana3 = Container.Resolve<Banana>("banana3");
        Console.WriteLine("banana3:" + banana3?.Name);

        Console.Read();
    }
}

实际上,Unity还有一些其他扩展方法,但主要都是围绕本文中介绍的几个方法做变形和扩展。有兴趣的朋友可以去了解。
然后这篇文章只是简单介绍如何如何使用Unity容器来注册和获取对象,下篇文章会介绍如何使用Unity实现依赖注入。

码字不易…点个赞吧~

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐