什么是依赖注入?
依赖注入解决了什么问题?
依赖注入是怎么使用的?
官方文档: 依赖关系注入 - .NET | Microsoft Docs
1.依赖注入是什么?
英文叫: Dependency Injection 简称DI
依赖关系注入 (DI) 是一种软件设计模式,这是一种在类及其依赖项之间实现控制反转 (IoC) 的技术。.NET 中的依赖关系注入是框架的内置部分,与配置、日志记录和选项模式一样。依赖项是指另一个对象所依赖的对象。
是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。
2.依赖注入解决了什么问题?
依赖关系注入通过以下方式解决了这些问题:
使用接口或基类将依赖关系实现抽象化。
在服务容器中注册依赖关系。 ASP.NET Core 提供了一个内置的服务容器 IServiceProvider。服务通常在应用启动时注册,并追加到 IServiceCollection。 添加所有服务后,可以使用 BuildServiceProvider 创建服务容器。 服务通常已在应用的 Program.cs 文件中注册。
将服务注入到使用它的类的构造函数中。 框架负责创建依赖关系的实例,并在不再需要时将其释放。
3.依赖注入是怎么使用的?
.net 内置DI框架的使用:
三种方式:(瞬时,范围,单例)所在包:Microsoft.Extensions.DependencyInjection;
AddTransient
AddScoped
AddSingleton
其他扩展方法:(多次添加不会报错)所在包:Microsoft.Extensions.DependencyInjection.Extensions;
TryAdd
TryAddTransient
TryAddScoped
TryAddSingleton
控制台程序使用依赖注入
文档示例方法:
using ConsoleDI.IEnumerableExample;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ConsoleDI.Example;
class Program
{
static Task Main(string[] args)
{
using IHost host = CreateHostBuilder(args).Build();
_ = host.Services.GetService<ExampleService>();
return host.RunAsync();
}
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
services.AddSingleton<IMessageWriter, ConsoleMessageWriter>()
.AddSingleton<IMessageWriter, LoggingMessageWriter>()
.AddSingleton<ExampleService>());
}
// 控制台中服务注册的另一种方法
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
services.AddScoped<ITestService>();
services.AddSingleton<ITestService, TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
var ts1 = sp.GetRequiredService<TestServiceImpl>();
var ts2 = sp.GetRequiredService<TestServiceImpl>();
Console.WriteLine(object.ReferenceEquals(ts1, ts2));
}
在.net WebApi项目中的应用
using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(builder.Configuration.GetSection(ColorOptions.Color));
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();
var app = builder.Build();
服务注册方法
框架提供了适用于特定场景的服务注册扩展方法:
方法 | 自动对象 (object)释放 | 多种实现 | 传递参数 |
Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>() 示例: services.AddSingleton(); | 是 | 是 | 否 |
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION}) 示例: services.AddSingleton(sp => new MyDep()); services.AddSingleton(sp => new MyDep(99)); | 是 | 是 | 是 |
Add{LIFETIME}<{IMPLEMENTATION}>() 示例: services.AddSingleton(); | 是 | 否 | 否 |
AddSingleton<{SERVICE}>(new {IMPLEMENTATION}) 示例: services.AddSingleton(new MyDep()); services.AddSingleton(new MyDep(99)); | 否 | 是 | 是 |
AddSingleton(new {IMPLEMENTATION}) 示例: services.AddSingleton(new MyDep()); services.AddSingleton(new MyDep(99)); | 否 | 否 | 是 |
// 这是一种工厂的创建方式,如果有传递参数的需求可以使用,一般第一种就可以满足 services.AddSingleton<IMyDep>(sp => new MyDep(99)); // 这种方式,DI框架不会管理对象的销毁,需要手动执行对象的销毁 services.AddSingleton(new MyDep());
避免使用服务定位器模式。 例如,可以使用 DI 代替时,不要调用 GetService 来获取服务实例:
// 不推荐使用服务定位器的方式获取服务,不推荐但是不代表绝对不能用 var myService = _service.GetService<IMyService>();
DI 是静态/全局对象访问模式的替代方法。 如果将其与静态对象访问混合使用,则可能无法意识到 DI 的优点。