如果我有这门课...
public class Something : ISomething
{
public string SomeText { get; }
public IAwesomeifier Awesomeifier { get; }
public Something(string someText, IAwesomeifier awesomeifier)
{
this.SomeText = someText ?? throw new ArgumentNullException(nameof(someText));
this.Awesomeifier = awesomeifier ?? throw new ArgumentNullException(nameof(awesomeifier));
}
// ... plus methods that actually do something...
}
...我想通过依赖注入来实例化它(使用
Microsoft.Extensions.Hosting
和Microsoft.Extensions.DependencyInjection
),someText
的值为“这是要awesome化的文本”,我可以使用ActivatorUtilities
来做到这一点像这样:
private static IHost BuildHost()
{
var builder = Host.CreateApplicationBuilder();
var services = builder.Services();
services.AddSingleton<IAwesomeifier, Awesomeifier>();
services.AddSingleton<ISomething>(provider =>
ActivatorUtilities.CreateInstance<Something>(
provider,
"Here's the text to be awesomeified"));
return builder.Build();
}
效果很好。然而,它似乎很脆弱并且容易出错。是否有一些与此类似的标准事物可以更明确地将参数与预期参数联系起来?
例如,我想可能是这样的:
services.AddSingleton<ISomething>(provider =>
ActivatorUtilities.CreateInstance<Something>(
provider,
someText: "Here's the text to be awesomeified"));
它看起来很脆弱并且容易出错。是否有一些与此类似的标准事物可以更明确地将参数与预期参数联系起来?
不,不幸的是,没有。我能看到更加类型安全的唯一方法是回退到直接构造函数调用并跳过此类型的自动装配。例如:
例如,我想可能是这样的:
services.AddSingleton<ISomething>(provider =>
new Something(
someText: "Here's the text to be awesomeified",
awesomeifier: provider.GetRequiredService<IAwesomeifier>()));
此注册在编译时是完全安全的,但这也意味着对
Something
构造函数的每次更改都需要反映在此注册中。
在您的代码示例中,您使用了
ActivatorUtilities.CreateInstance
。此方法会自动为您找出需要注入哪些依赖项。它的行为类似于 AddSingleton<ISomething, Something>()
的行为,例如:DI 容器自动找出要注入的依赖项。这种技术通常称为自动接线。
使用自动装配更改在引入依赖项时必须更新此注册,这可能会使您的 DI 配置更易于维护。正如您已经意识到的那样,缺点是会失去编译时安全性。
但是还有其他选择需要考虑。对Something
的小重构完全规避了这个问题:
Something
通过这个解决方案,原始类型
public record SomethingConfiguration(string SomeText);
public class Something : ISomething
{
public SomethingConfiguration Config { get; }
public IAwesomeifier Awesomeifier { get; }
public Something(SomethingConfiguration config, IAwesomeifier awesomeifier)
{
this.Config = config ?? ...;
this.Awesomeifier = awesomeifier ?? ...;
}
// ... plus methods that actually do something...
}
被包装在类中,可以更精确地定义
string
的含义,即具有配置值。这使您可以将 DI 配置简化为以下内容:Something