依赖注入 - 在重载的构造函数中放置逻辑?

时间:2009-06-26 07:43:24

标签: c# .net dependency-injection inversion-of-control mocking

今天我上了这堂课:

public class SmtpEmailProvider : IMessageProvider
{
    private readonly SmtpClientWrapper _smtpClientWrapper;

    public SmtpEmailProvider(SmtpClientWrapper smtpClientWrapper)
    {
        _smtpClientWrapper = smtpClientWrapper;
    }

为了能够模拟SmtpClient,我把它包装成这样:

public class SmtpClientWrapper
{
    private readonly SmtpClient _smtpClient;

    public SmtpClientWrapper(SmtpClient smtpClient)
    {
        _smtpClient = smtpClient;
    }

    public virtual void Send(MailMessage msg)
    {
        if (_smtpClient == null) throw new InvalidOperationException("SmtpClient must be passed to the constructor before calling Send.");

        _smtpClient.Send(msg);
    }
}

现在我可以这样做来启动SmtpEmailProvider类,并将SmtpClient逻辑放在那里:

public IMessageProvider LocateProviderByName(string providerName)
{
    var client = new SmtpClient
                     {
                         Host = "127.0.0.1",
                         Port = 25
                     };
    client.Credentials = new NetworkCredential("...", "...");
    return new SmtpEmailProvider(new SmtpClientWrapper(client));
}

但我想用以下内容代替:

public IMessageProvider LocateProviderByName(string providerName)
{
    return IoC.Resolve<IMessageProvider>(providerName);
}

然后我需要将逻辑放在没有参数的构造函数中。但我觉得我在构造函数中做的很多。

还有其他办法吗?

1 个答案:

答案 0 :(得分:2)

我对你想要完成的事情感到有点困惑。如果我假设您需要提供Smtp电子邮件,并且您正在使用IoC,那么您应该使用IoC框架创建并连接整个对象图。通过这种方式,我的意思是你要配置你的IoC框架来创建SmtpClient,然后用它创建SmtpClientWrapper,最后用它创建SmtpEmailProvider。您不需要在SmtpEmailProvider构造函数中放置任何依赖关系创建逻辑。

根据您提供的代码,以下是Castle Windsor的示例:

<configuration>
  <component id="smtpClient" type="System.Net.Mail.SmtpClient, System">
    <parameters>
      <Host>127.0.0.1</Host>
      <Port>25</Port>
    </parameters>
  </component>
  <component id="smtpClientWrapper" type="Naespace.SmtpClientWrapper, Assembly">
    <parameters>
      <smtpClient>${smtpClient}</smtpClient>
    </parameters>
  </component>
  <component id="smtpProvider" service="Namespace.IMessageProvider, Assembly" type="Namespace.SmtpEmailProvider, Assembly">
    <parameters>
      <smtpClientWrapper>${smtpClientWrapper}</smtpClientWrapper>
    </parameters>
  </component>
</configuration>

使用上面的Windsor配置,您可以像这样简单地创建IMessageProvider:

public IMessageProvider LocateProviderByName(string providerName)
{
    return IoC.Resolve<IMessageProvider>(providerName);
}

var messageProvider = LocateProviderByName("smtpProvider");

这里的关键点是使用IoC容器:依赖项创建和管理系统,可以而且应该为您创建完整的对象图。这缓解了构造函数中过多依赖管理逻辑的问题。