如何在GetInstance调用/替代解决方案之后在Simple Injector中进行注册?

时间:2014-12-04 07:32:16

标签: c# ioc-container simple-injector

考虑以下示例:

public class CommunicationClient : IClient
{
    public CommunicationClient(IServerSettings settings) { ... }
    // Code         
}

public class SettingsManager : ISettingsManager
{
    SettingsManager(IDbSettingManager manager)

    // Code
    public IDictionary<string, string> GetSettings() { ... }
}

问题: 在执行注册时(使用SimpleInjector),我需要提供从SetingsManager实例和填充ServerSettings实例(IServerSettings的具体类型)获取的值,但如果我在注册GetInstance<ISettingsManager>之前致电CommunicationClient,它会给我一个我无法做到的错误 的错误第一次调用GetInstance,GetAllInstances和Verify后,容器无法更改。

一种解决方案可能是将ISettingsManager作为依赖项注入CommunicationClient但我真的不想传递它,因为它会提供超过所需信息。

编辑:容器注册

container.Register(typeof(ICommunicationClient), typeof(CommunicationClient));
ISettingsManager settingsManager = container.GetInstance<ISettingsManager>();

string url = settingsManager.GetSetting("url");
string userName = settingsManager.GetSetting("username");
string password = settingsManager.GetSetting("password");

container.Register(typeof(IServerConfiguration), () => 
      new ServerConfiguration(url, userName, password);

有关如何以更清洁的方式实现上述目标的任何建议/替代解决方案?感谢。

2 个答案:

答案 0 :(得分:6)

Simple Injector在首次使用后锁定容器以进行进一步更改。这是一个明确的设计选择,描述为here。这意味着您在致电Register后无法致电GetInstance,但绝不应该有理由这样做。或者换句话说,您的配置始终可以以您不需要的方式重写。在您的情况下,您的配置可能如下所示:

var settingsManager = new SettingsManager(new SqlSettingManager("connStr"));

container.RegisterSingle<ISettingsManager>(settingsManager);
container.Register<ICommunicationClient, CommunicationClient>();

string url = settingsManager.GetSetting("url");
string userName = settingsManager.GetSetting("username");
string password = settingsManager.GetSetting("password");

container.Register<IServerConfiguration>(() => 
      new ServerConfiguration(url, userName, password));

在那里,您看到SettingsManager未由容器构建。使用DI容器时,不需要让DI容器为您构建每个实例。让容器自动连线实例可以降低Composition Root的维护负担,并且可以更轻松地将横切关注点(例如使用装饰器)应用于相关类组。对于SettingsManagerSqlSettingsManager类,它们的构造函数不太可能经常更改它会增加Composition Root的维护负担。因此,手动创建这些实例一次非常好。

答案 1 :(得分:1)

如果我理解正确,要创建CommunicationClient课程,您需要传递通过在ISettingsManager的实例上调用方法检索的信息,但您不想将ISettingsManager作为依赖关系传递给您的CommunicationClient

对此的一个解决方案是创建和注册一个工厂,该工厂将依赖ISettingsManager并且将具有将返回已配置客户端的CreateClient方法。

public class CommunicationClientFactory : ICommunicationClientFactory
{
   public CommunicationClientFactory(ISettingsManager settingsManager) {...}

   public CreateClient() {...}
}

这样,您的CommunicationClient不依赖于ISettingsManager,而您只有这家工厂负责创建您的实例。

编辑: 另一种方法是,如果您不想为此创建工厂,则可以在&#34;无效&#34;中创建CommunicationClient对象。 state,并有一个方法可以设置设置并使其状态有效。

类似的东西:

public class CommunicationClient : IClient
{
    public CommunicationClient() { ... }
    // Code

    CommunicationClient WithSettings(IServerSettings settings) { ... }
}

当然,您必须确保用户在尚未通过设置时不使用它,如果情况确实如此,可能会发送异常。我更喜欢这个解决方案,因为它不太明确,你需要这些设置让你的对象处于正确的状态。