Dea*_*n P 0 c# design-patterns dependency-injection di-containers .net-core
我有一个控制台 .NET 核心应用程序,它使用该Microsoft.Extensions.DependencyInjection库作为依赖项注入框架。
我想使用这个框架来注入一个“向下”两个级别的依赖项,而不必在中间层多余地提及这个依赖项。我该怎么做呢?
目前,我注入依赖项的唯一方法是将其向下传递,直到需要为止。这是我的独立控制台应用程序,它演示了该要求。它是一个简单的程序,可以根据示例资产和负债金额计算一个人的净资产。(它实际上只是减去两个金额)。
该Program.cs文件包含程序主入口点并注册依赖项。
程序.cs:
public class Program
{
private static IServiceProvider _serviceProvider;
public static void Main(string[] args)
{
RegisterServices();
IServiceScope scope = _serviceProvider.CreateScope();
scope.ServiceProvider.GetRequiredService<ConsoleApplication>().Run();
DisposeServices();
}
private static void RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<ICalculator, Calculator>();
services.AddSingleton<ConsoleApplication>();
_serviceProvider = services.BuildServiceProvider(true);
}
private static void DisposeServices()
{
if (_serviceProvider == null)
{
return;
}
if (_serviceProvider is IDisposable)
{
((IDisposable)_serviceProvider).Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
设置依赖项注入后,Program.cs运行该ConsoleApplication.cs Run方法。
ConsoleApplication.cs:
internal class ConsoleApplication
{
private readonly ICalculator _calculator;
public ConsoleApplication(ICalculator calculator)
{
_calculator = calculator;
}
public void Run()
{
Person person = new Person(_calculator)
{
Assets = 1000m,
Liabilities = 300m
};
Console.WriteLine(person.GetNetWorth());
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码实例化了一个示例Person并调用该GetNetWorth方法。Person 类如下所示。
人.cs:
public class Person
{
private readonly ICalculator _calculator;
public Person(ICalculator calculator)
{
_calculator = calculator;
}
public decimal Assets {get; set;}
public decimal Liabilities {get; set;}
public decimal GetNetWorth()
{
decimal netWorth = _calculator.Subtract(Assets, Liabilities);
return netWorth;
}
}
Run Code Online (Sandbox Code Playgroud)
该类具有如下所示的Person依赖关系:Calculator
计算器.cs:
public interface ICalculator
{
decimal Add(decimal num1, decimal num2);
decimal Subtract(decimal num1, decimal num2);
decimal Multiply(decimal num1, decimal num2);
decimal Divide(decimal num1, decimal num2);
}
public class Calculator : ICalculator
{
public decimal Add(decimal num1, decimal num2) => num1 + num2;
public decimal Subtract(decimal num1, decimal num2) => num1 - num2;
public decimal Multiply(decimal num1, decimal num2) => num1 * num2;
public decimal Divide(decimal num1, decimal num2) => num1 / num2;
}
Run Code Online (Sandbox Code Playgroud)
鉴于上面的程序,您可以看到这里的问题是该类ConsoleApplication.cs有这行代码:
private readonly ICalculator _calculator;
public ConsoleApplication(ICalculator calculator)
{
_calculator = calculator;
}
Run Code Online (Sandbox Code Playgroud)
该代码是多余的,应该避免,因为ConsoleApplication.cs 没有这种依赖性,因此不应该了解它的任何信息。Person我被迫包含它的唯一原因是将其传递到需要依赖项的下一个级别。
通过上面的示例,如何调整program.cs以避免传递依赖项?我有一种感觉,我使用的Microsoft.Extensions.DependencyInjection框架完全错误。使用 DI 容器的全部目的就是为了规避这个问题。我可能根本就没有使用过 DI 容器,这样代码会更简单。
我读过很多询问类似问题的帖子。但是,它们不适合我的控制台应用程序、.NET 和使用Microsoft.Extensions.DependencyInjection;DI 框架的具体情况。
这是一个设计问题。Person类根据运行时数据显示 SRP(单一职责原则)/SOC(关注点分离)违规和 DI 代码气味。(基于提供的简化示例)。
将运行时数据注入应用程序组件是一种代码味道。运行时数据应该流经已构造的对象图的方法调用。
请注意如何使用运行时数据构造此类。
public class Person {
private readonly ICalculator _calculator;
public Person(ICalculator calculator) {
_calculator = calculator;
}
public decimal Assets {get; set;} //<--Run-time data
public decimal Liabilities {get; set;} //<--Run-time data
public decimal GetNetWorth() {
decimal netWorth = _calculator.Subtract(Assets, Liabilities);
return netWorth;
}
}
Run Code Online (Sandbox Code Playgroud)
创建一个单独的服务,其职责是在运行时获取一个人并计算他们的净值
//Run-time data
public class Person {
public decimal Assets {get; set;}
public decimal Liabilities {get; set;}
}
//Service abstraction
public interface IPersonNetWorthService {
decimal GetNetWorth(Person person);
}
//Service implementation
public class PersonNetWorthService : IPersonNetWorthService {
private readonly ICalculator _calculator;
public PersonNetWorthService(ICalculator calculator) {
_calculator = calculator;
}
public decimal GetNetWorth(Person person) {
decimal netWorth = _calculator.Subtract(person.Assets, person.Liabilities);
return netWorth;
}
}
Run Code Online (Sandbox Code Playgroud)
控制台应用程序现在可以干净地执行其功能,没有任何违规和代码异味
internal class ConsoleApplication
{
private readonly IPersonNetWorthService calculator;
public ConsoleApplication(IPersonNetWorthService calculator) {
this.calculator = calculator;
}
public void Run() {
Person person = new Person() {
Assets = 1000m,
Liabilities = 300m
};
Console.WriteLine(calculator.GetNetWorth(person));
}
}
Run Code Online (Sandbox Code Playgroud)
记住注册所有依赖项
private static void RegisterServices() {
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IPersonNetWorthService, PersonNetWorthService>();
services.AddSingleton<ICalculator, Calculator>();
services.AddSingleton<ConsoleApplication>();
_serviceProvider = services.BuildServiceProvider(true);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
905 次 |
| 最近记录: |