structuremap - 同一接口的两个实现

Myl*_*ell 12 c# structuremap dependency-injection inversion-of-control

我有一个服务类与以下ctor:

public class (IMessageService emailService, IMessageService smsService)
{ ... }
Run Code Online (Sandbox Code Playgroud)

IMessageService(电子邮件和短信)的两个实现.如何配置容器以正确解析此构造函数?这是命名实例进入的地方,还是另一种情况?

Nig*_*888 31

可以使用命名实例或智能实例来解决此问题...

// Named instances
this.For<IMessageService>().Use<EmailService>().Named("emailService");
this.For<IMessageService>().Use<SmsService>().Named("smsService");



// Smart instances
var emailService = this.For<IMessageService>().Use<EmailService>();
var smsService = For<IMessageService>().Use<SmsService>();

this.For<ISomeService>().Use<SomeService>()
    .Ctor<IMessageService>("emailService").Is(emailService)
    .Ctor<IMessageService>("smsService").Is(smsService);
Run Code Online (Sandbox Code Playgroud)

但我认为你的设计需要一些工作.您的服务知道电子邮件服务和SMS服务之间的区别是违反Liskov替换原则的事实.比注入相同类型的2个参数更好的方法是使用复合模式.

public class CompositeMessageService : IMessageService
{
    private readonly IMessageService messageServices;

    public CompositeMessageService(IMessageService[] messageServices)
    {
        if (messageServices == null)
            throw new ArgumentNullException("messageServices");
        this.messageServices = messageServices;
    }

    public void Send(IMessage message)
    {
        foreach (var messageService in this.messageServices)
        {
            messageService.Send(message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么您的原始服务只需要接受一个实例IMessageService.它不需要知道IMessageService它正在处理什么类型的细节.

public SomeService(IMessageService messageService)
Run Code Online (Sandbox Code Playgroud)

在StructureMap中,您可以轻松注册IMessageService的所有实例,它会自动将它们注入IMessageService的构造函数参数数组中.

this.Scan(scan =>
        {
            scan.TheCallingAssembly();
            scan.AssemblyContainingType<IMessageService>();
            scan.AddAllTypesOf<IMessageService>();
        });
Run Code Online (Sandbox Code Playgroud)

或者您可以显式注入实例.

        this.For<IMessageService>().Use<CompositeMessageService>()
            .EnumerableOf<IMessageService>().Contains(x =>
            {
                x.Type<EmailService>();
                x.Type<SmsService>();
            });
Run Code Online (Sandbox Code Playgroud)

这意味着您的配置可以更改为更改首先调用哪个服务的顺序.根据您当前的设计,这些细节将硬编码到接受2个参数的服务中.

此外,您还可以在不更改设计的情况下添加其他消息服务或删除现有消息服务.

  • 简短回答 - 具有多个相同类型依赖关系的服务是代码气味,可以使用复合或装饰器.至于进入正确的心态,我个人通过阅读[.NET中的依赖注入](http://www.manning.com/seemann/)和一些试验和错误来到那里.设计模式可以解决很多问题,而DI本身就无法解决,而且这本书非常适合教授何时以及如何应用这些模式. (4认同)