如何根据构造函数参数名称注入适当的依赖项

Use*_*ser 6 c# dependency-injection castle-windsor

我有这个接口被少数具体类型使用,例如EmailFormatter,TextMessageFormatter等等.

public interface IFormatter<T>
{
    T Format(CompletedItem completedItem);
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题EmailNotificationService是,我想要注入EmailFormatter.此服务的构造函数签名是public EmailNotificationService(IFormatter<string> emailFormatter).

我很确定我之前已经看过这个,但我如何在Windsor中注册它,以便EmailFormatter在构造函数参数名称为emailFormatter?时注入?

这是我的温莎注册码.

container.Register(Component.For<IFormatter<string>>().ImplementedBy<EmailFormatter>());
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 9

请勿尝试在DI配置中解决此问题.相反,在应用程序的设计中解决它.在我看来,你已经使用相同的界面定义了几个不同的东西.你的要求很明显,因为你说:

我想注入EmailFormatter

你不想注入格式化程序; 你想注入一个电子邮件格式化程序.换句话说,你违反了Liskov替代原则.在应用程序中修复此问题.定义一个IEmailFormatter接口,让EmailNotificationService依赖于此:

public interface IEmailFormatter
{
    string Format(CompletedItem completedItem);
}

public class EmailNotificationService
{
    public EmailNotificationService(IEmailFormatter formatter)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

这有两个重要的优点:

  1. 它使代码更易于维护,因为现在很清楚什么样的依赖EmailNotificationService实际存在.
  2. 它使DI配置更容易,更易于维护.只要看看Zach答案的依赖注册,你就会理解我在说什么.

  • @User:让`EmailNotificationService`依赖于`IFormatter <string>`意味着任何字符串格式化程序都可以正常工作,而它只能与可以输出邮件的格式化程序一起正常工作.那么`EmailNotificationService`关注的是不一样的.虽然`IMailFormatter`和`IFormatter <string>`具有相同的输入和输出类型,但是`IMailFormatter`的契约更强,因为它明确地说明它返回什么类型的字符串,而`IFormatter <string>`可以什么都归还 (2认同)

小智 6

服务代码:

public EmailNotificationService(IFormatter<string> emailFormatter){...}
Run Code Online (Sandbox Code Playgroud)

依赖注册码:

container.Register(
    Component.For<IFormatter<string>().ImplementedBy<TextMessageFormatter>().Named("TextMessageFormatter"),
    Component.For<IFormatter<string>().ImplementedBy<EmailFormatter>().Named("EmailFormatter"),
    Component.For<INotificationService>().ImplementedBy<EmailNotificationService>().ServiceOverrrides(
        ServiceOverride.ForKey("emailFormatter").Eq("EmailFormatter"))
);
Run Code Online (Sandbox Code Playgroud)