Code Copied

Unity系列教程(四)Register和Resolve全解析

Unity提供了很多的Register和Reslove方式,本文对Register和Resolve做了一个较为全面的解析。

下面的示例中包含以下内容:

  • 实例注册
  • 简单类型注册
  • 泛型和非泛型注册
  • 单个构造器注册
  • 多个构造器注册
  • 重写参数
  • 惯例注册

源码下载:Download

1. 实例注册

1.1 单例注册

DbContext代码:

public class DbContext
{
    public DbContext()
    {
        Console.WriteLine("This is Dbcontext...");
    }
}

Register代码:

var context = new DbContext();
container.RegisterInstance(context);

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var dbContext1 = container.Resolve(typeof (DbContext));
    Console.WriteLine("..........................................................");
    var dbContext2 = container.Resolve(typeof(DbContext));
}

运行结果:

image

1.2 冗余的实例注册

如果将Register代码作出更改,Resolve代码不变

container.RegisterInstance(typeof(DbContext));

通过运行结果可以知道,这和直接调用了2次DbContext的构造方法没什么区别。
Register代码在这里是冗余的,把Register代码去掉,程序仍然能够正常运行。
image

2. 泛型和非泛型注册

IService代码:

public interface IService
{
    void Output();
}

DataService代码:

public class DataService : IService
{
    public void Output()
    {
        Console.WriteLine("This is data service...");
    }
}

LoggingService代码:

public class LoggingService : IService
{
    public void Output()
    {
        Console.WriteLine("This is logging service...");
    }
}

2.1 泛型Register和Resolve

Register代码:

// 泛型注册
container.RegisterType<IService, DataService>();
break;

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var service = container.Resolve<IService>();
    service.Output();
    Console.WriteLine("..........................................................");
}

运行结果:

image

2.2 非泛型Register和Resolve

Register代码:

// 非泛型注册
container.RegisterType(typeof(IService), typeof(DataService));

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var service = (IService)container.Resolve(typeof(IService));
    service.Output();
    Console.WriteLine("..........................................................");
}

运行结果:

image

3. 根据名称注册和解析

Register代码:

container.RegisterType<IService, DataService>("Data");
container.RegisterType<IService, LoggingService>("Logging");

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var service1 = container.Resolve<IService>("Data");
    Console.WriteLine("service1调用Output...");
    service1.Output();
    var service2 = container.Resolve<IService>("Logging");
    Console.WriteLine("service2调用Output...");
    service2.Output();
    Console.WriteLine("..........................................................");
}

运行结果:

image

4. 构造器注册

构造器注入是Unity的默认注册行为。下面演示不同情况下构造器注入的方式。

IBusinessManager代码:

public interface IBusinessManager
{
    void DoBusiness();
}

4.1 单个构造器自动注册

BusinessManager代码:

public class BusinessManager : IBusinessManager
{
    private readonly IService _service;
    public BusinessManager(DataService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public void DoBusiness()
    {
        Console.WriteLine("Business manager do the business...");
        _service.Output();
    }
}

Register代码:

container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>();
container.RegisterType<IBusinessManager, BusinessManager>();

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var bm = container.Resolve<IBusinessManager>();
    bm.DoBusiness();
    Console.WriteLine("..........................................................");
}

运行结果:

SNAGHTMLa58091a

4.2 多个构造器注册

1. 有多个最大参数数量的构造器,使用InjectionConstructor特性

BusinessManager代码:

public class BusinessManager : IBusinessManager
{
    private readonly IService _service;
    public BusinessManager(DataService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public BusinessManager(LoggingService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public void DoBusiness()
    {
        Console.WriteLine("Business manager do the business...");
        _service.Output();
    }
}

Register代码:

container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>();
container.RegisterType<IBusinessManager, BusinessManager>();

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var bm = container.Resolve<IBusinessManager>();
    bm.DoBusiness();
    Console.WriteLine("..........................................................");
}

在运行时,会产生异常,因为UnityContainer不知道该用哪一个构造器实例化BusinessManager对象,异常信息如下:

Microsoft.Practices.Unity.ResolutionFailedException was unhandled
  HResult=-2146233088
  Message=Resolution of the dependency failed, type = "AllAboutRegistrationConsoleApp.Managers.BusinessManager", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type BusinessManager has multiple constructors of length 1. Unable to disambiguate.

image

这时我们需要在相同数量的最多参数的构造器中指定一个InjectionConstructor。

BusinessManager代码:

public class BusinessManager : IBusinessManager
{
    private readonly IService _service;

    public BusinessManager(DataService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    [InjectionConstructor]
    public BusinessManager(LoggingService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public void DoBusiness()
    {
        Console.WriteLine("Business manager do the business...");
        _service.Output();
    }
}

这里指定了LogginService作为参数的构造器作为InjectionConstructor,所以运行结果如下:

SNAGHTMLa6d95ee

2. 有多个最大参数数量的构造器,不指定InjectionConstructor特性,使用Parameter Overrides。

BusinessManager提供了2个具有相同参数数量的构造器,我们希望这2个构造器都能发挥作用,而不是每次实例化时都调用BusinessManager(LoggingService service)这个构造器。
BusinessManager代码:

public class BusinessManager : IBusinessManager
{
    private readonly IService _service;

    public BusinessManager(DataService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public BusinessManager(LoggingService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public void DoBusiness()
    {
        Console.WriteLine("Business manager do the business...");
        _service.Output();
    }
}

Register代码:

container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>();
container.RegisterType<IBusinessManager, BusinessManager>("Business-Data",
    new InjectionConstructor(typeof (DataService)));
container.RegisterType<IBusinessManager, BusinessManager>("Business-Logging",
    new InjectionConstructor(typeof(LoggingService)));

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var businssData = container.Resolve<IBusinessManager>("Business-Data");
    Console.WriteLine("businssData调用DoBusiness...");
    businssData.DoBusiness();
    Console.WriteLine("..........................................................");
    var businssLogging = container.Resolve<IBusinessManager>("Business-Logging");
    Console.WriteLine("businssLogging调用DoBusiness...");
    businssLogging.DoBusiness();
    Console.WriteLine("..........................................................");
}

运行结果:

SNAGHTMLa8ad253

3. 仅有1个最大参数数量的构造器

BusinessManager代码:

public class BusinessManager : IBusinessManager
{
    private readonly IService _service;
    private readonly IService _dataService;
    private readonly IService _loggingService;

    public BusinessManager(DataService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public BusinessManager(LoggingService service)
    {
        _service = service;
        Console.WriteLine("This is business manager...");
    }

    public BusinessManager(DataService dataService, LoggingService loggingService)
    {
        _dataService = dataService;
        _loggingService = loggingService;
        Console.WriteLine("This is business manager...");
        Console.WriteLine("Business manager do the business...");
        _dataService.Output();
        _loggingService.Output();
    }

    public void DoBusiness()
    {
        Console.WriteLine("Business manager do the business...");
        _service.Output();
    }
}

Register代码:

container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>();
container.RegisterType<IBusinessManager, BusinessManager>();

Resolve代码:

UnityConfig.RegisterTypes(container, Case);
Console.WriteLine("..........................................................");
var bm = container.Resolve<IBusinessManager>();
Console.WriteLine("..........................................................");

实例化BusinessManager时会调用参数数量最多的构造器:

image
运行结果:

SNAGHTMLa9cef55

4. 构造器注入总结

  • 目标class只有一个构造器,在Resolve时自动调用该构造器
  • 目标class有多个构造器,且只有一个参数数量最大的构造器时,在Resolve时自动调用这个参数数量最大的构造器。
  • 目标class有多个构造求,且有多个参数数量最大的构造器时,需要使用InjectionConstructor特性或者在Register时指定InjectionMember。

5. 惯例注册

Register代码:

// 注册命名空间AllAboutRegistrationConsoleApp.Managers下的所有接口和具体类的mapping关系
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies()
        .Where(a => a.Namespace == "AllAboutRegistrationConsoleApp.Managers"),
    WithMappings.FromAllInterfaces,
    WithName.Default,
    WithLifetime.ContainerControlled);

// 由于IService存在多个具体类的mapping关系,属于非”惯例“性的,所以需要单独注册
container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>();

Resolve代码:

using (var container = new UnityContainer())
{
    UnityConfig.RegisterTypes(container, Case);
    Console.WriteLine("..........................................................");
    var bm = container.Resolve<IBusinessManager>();
    Console.WriteLine("..........................................................");
}

运行结果:

SNAGHTMLa9cef55

惯例注册的用法也可以参照我的上一篇文章:Unity系列教程(三)Registration by Convention

6. 参考和下载

参考链接:

Annotating Objects for Constructor Injection
Dependency Injection with Unity
Software Architecture-Dependency Injection with Unity for Constructor Injection

源码下载:Download