如何在 GetInstance 调用/备用解决方案后在简单注入器中进行注册

本文关键字:注入器 简单 注册 解决方案 GetInstance 调用 备用 | 更新日期: 2023-09-27 18:33:07

请考虑以下示例:

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的具体类型(,但是如果我在注册CommunicationClient之前调用GetInstance<ISettingsManager>,它会给我一个错误,我无法这样做
错误容器在首次调用 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);

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

如何在 GetInstance 调用/备用解决方案后在简单注入器中进行注册

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

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 容器为您构建每个实例。让容器自动连接实例是为了减轻组合根的维护负担,并更轻松地将横切关注点(例如使用装饰器(应用于相关类组。对于 SettingsManagerSqlSettingsManager 类,它们的构造函数不太可能经常更改,从而增加组合根的维护负担。因此,手动创建这些实例一次是完全可以的。

如果我

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

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

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

这样,您的CommunicationClient就不依赖于ISettingsManager,并且您只有这个工厂来执行创建实例的工作。

编辑:如果您不想为此创建工厂,另一种方法是在"无效"状态下创建CommunicationClient对象,并有一个方法来设置设置并使其状态有效。

像这样:

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

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