如何在 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
后无法呼叫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 容器为您构建每个实例。让容器自动连接实例是为了减轻组合根的维护负担,并更轻松地将横切关注点(例如使用装饰器(应用于相关类组。对于 SettingsManager
和 SqlSettingsManager
类,它们的构造函数不太可能经常更改,从而增加组合根的维护负担。因此,手动创建这些实例一次是完全可以的。
理解正确,要创建您的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) { ... }
}
当然,您必须确保用户在尚未传递设置时不使用它,如果是这种情况,可能会发送异常。我不太喜欢这个解决方案,因为您需要这些设置才能使对象处于正确的状态不太明确。