依赖注入容器Unity Application Block快速入门

概述

Unity是微软模式与实践团队开发的一个轻量级、可扩展的依赖注入容器,之前我也有过一篇文章《Enterprise Library 4.0中的依赖注入容器(Unity)预览》对其做过介绍。微软模式与时间团队已经在2月份发布了Unity February 2008 CTP版本,官方主页是:http://www.codeplex.com/unity,大家可以到网站上去下载相关的源代码。本文将通过一些示例让您对Unity使用有一个逐步的认识和了解。

准备相关代码

为了接下来的说明,我们先编写几个后面需要的接口和类:

接口ILogger

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

FlatFileLogger类

public class FlatFileLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("Message:{0}", message));
        Console.WriteLine("Target:FlatFile");
    }
}

DatabaseLogger类

public class DatabaseLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("Message:{0}",message));
        Console.WriteLine("Target:Database");
    }
}

创建容器

在Unity中创建容器实例有两种方法,一是直接使用构造函数创建,如下代码所示:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
    }
}

第二种通过父容器创建容器,在Unity中提供了层级容器的创建,即可以通过父容器来逐级创建容器:

Unity_TerryLee_001

图1 Unity中层级容器

通过父容器来创建容器可以使用CreateChildContainer:

class Program
{
    static void Main(string[] args)
    {
        UnityContainer parentContainer = new UnityContainer();

        UnityContainer childContainer = parentContainer.CreateChildContainer();
    }
}

采用层级容器的好处是我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。

class Program
{
    static void Main(string[] args)
    {
        UnityContainer parentContainer = new UnityContainer();

        UnityContainer childContainer = parentContainer.CreateChildContainer();

        // can use both generated objects here

        // Dispose child container
        childContainer.Dispose();

        // can use only object in parent container here

        // Dispose parent container
        parentContainer.Dispose();
    }
}

注册接口映射

在Unity中提供了Register方法供我们在容器中注册接口映射:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, DatabaseLogger>();
        container.Register<ILogger, FlatFileLogger>("flatfileLogger");
    }
}

第一个泛型参数是基类型,第二个泛型参数是组件类型,它们之间必须满足一定的泛型约束关系:

IUnityContainer Register<TFrom, TTo>() where TTo : TFrom;

另外,如果在注册组件时没有指定我们也可以使用非泛型的Register方法进行接口映射:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.Register(typeof(ILogger),typeof(DatabaseLogger));
        container.Register(typeof(ILogger),typeof(FlatFileLogger),"flatfileLogger");
    }
}

获取对象实例

在Unity中提供了Get方法用以获取对象实例,如下代码所示:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, FlatFileLogger>();

        ILogger logger =  container.Get<ILogger>();

        logger.Write("TerryLee");
    }
}

在上面代码中,我们在容器中注册了一个ILogger接口到FlatFileLogger的映射,当调用Get<ILogger>()方法时,将返回ILogger的一个默认的类型实例。运行代码可以看到:

Unity_TerryLee_002

在之前注册接口映射部分,Register方法有一个重载是为接口映射指定一个特定的名称,这样我们可以根据名称和接口来获取一个特定类型的对象实例,如下面的代码我们同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并未DatabaseLogger指定一个名称,在使用Get方法的时候就可以通过ILogger和指定的名称来获取DatabaseLogger实例:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, FlatFileLogger>();
        container.Register<ILogger, DatabaseLogger>("databaseLogger");

        ILogger logger = container.Get<ILogger>("databaseLogger");

        logger.Write("TerryLee");
    }
}

再运行代码,可以看到获取到了DatabaseLogger实例:

Unity_TerryLee_003

如果我们同时同时注册FlatFileLogger和DatabaseLogger到接口ILogger的映射,并且不指定任何名称,那么直接调用Get方法将会返回后注册的组件的对象实例,如下面的代码:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, FlatFileLogger>();
        container.Register<ILogger, DatabaseLogger>();

        ILogger logger = container.Get<ILogger>();

        logger.Write("TerryLee");
    }
}

运行后会返回DatabaseLogger实例:

Unity_TerryLee_003

当然我们也可以使用非泛型的Get方法来获取对象实例:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, FlatFileLogger>();

        ILogger logger = container.Get(typeof(ILogger)) as ILogger;

        logger.Write("TerryLee");
    }
}

获取所有对象实例

除了可以获取单个对象实例之外,我们还可以一次获取容器中所有与某一接口映射的所有对象实例,但是需要依赖于在注册映射时提供的名称,如果没有指定名称,通过GetAll方法不会被获取到。

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.Register<ILogger, FlatFileLogger>();
        container.Register<ILogger, FlatFileLogger>("flatFileLogger");
        container.Register<ILogger, DatabaseLogger>("DatabaseLogger");
        IEnumerable<ILogger> loggers = container.GetAll<ILogger>();

        foreach (ILogger logger in loggers)
        {
            if (null != logger)
            {
                Console.WriteLine(logger.GetType().ToString());
            }
        }
    }
}
运行后如下,第一个没有提供名称的类型实例不会被获取到:
Unity_TerryLee_004

结束语

关于Unity的一个简单使用就到这里了,希望能够对大家有用。使用Unity简单来说分为创建容器、注册接口映射、获取对象实例这样三步,在下篇文章中,将会说到如何使用配置文件注册接口映射以及如何注册Singleton实例等内容。

posted @ 2008-02-21 23:35  TerryLee  阅读(27577)  评论(79编辑  收藏  举报