我经常遇到一个问题,即一个类需要一个依赖项和一些字符串值来初始化。例如,请考虑以下代码:
public class CustomerService
{
public CustomerService(ITcpConnection connection, string realm)
{
}
}
问题在于,由于附加的字符串参数,从DI容器中取出它并不容易。解决此问题的最佳方法是什么?这些是我能想到的方式:
答案 0 :(得分:2)
最好避免在同一构造函数中混合原语/配置值和(服务)依赖项。它们使DI配置复杂化,并且经常导致不可读且易碎Composition Root。
请执行以下操作:
摘要配置值
当将相同的值注入多个服务时,通常会丢失抽象。一个很好的例子是在所有存储库中注入string connectionString
值。在这种情况下,应用程序缺少IConnectionFactory
抽象(或相关的东西)。应该将连接字符串注入IConnectionFactory
实现(可能只将该连接字符串作为其构造函数参数),而不是将连接字符串注入到许多服务中,并让其他服务依赖于IConnectionFactory
而不是string
。
将配置值移至属性
通过将配置值从构造函数移动到属性,构造函数将只包含可以明确解析的类型,这意味着DI框架可以自动连接该构造函数,而不需要任何特殊的 - 最重要的是脆弱的 - 配置。您当然必须连接该构造函数,但大多数DI容器都有一种简单的方法,可以安全地编译,并且可以验证编译时。以下是Simple Injector的示例:
container.Register<IUnitOfWork, UnitOfWork>();
container.RegisterInitializer<UnitOfWork>(
instance => instance.ConnectionTimeOut = TimeSpan.FromSeconds(30));
以下是Autofac的示例:
builder.RegisterType<UnitOfWork>() .OnActivating(e =>
e.Instance.ConnectionTimeOut = TimeSpan.FromSeconds(30));
创建子类型
当属性注入不是一个选项时(例如,因为你不能更改源代码),你可以派生一个放在你的Composition Root中的子类型,并定义正确的构造函数并注册该子类型:
public class MyService : SomeExternalService
{
public MyService(ISomeDependency dep) : base(dep, "My Config Value") { }
}
// Registration
container.Register<IService, MyService>();