依赖注入
1.控制反转
依赖注入(DI)是控制反转(IOC)思想的实现方式,简化了模块的组装过程,降低模块之间的耦合度。
控制反转:怎样创建XX对象——>我要XX对象
两种实现方式:
1)服务定位器,类似:IDbConnection conn=ServiceLocator.GetService<IDbConnection>() //向框架主动获取
2)依赖注入,类似:public IDbConnection Conn{get;set;} //只需要声明,框架自动注入
2.依赖注入(DI)
服务:是IOC容器管理的对象。
服务容器:负责管理注册的服务
查询服务:创建对象及关联对象。
服务生命周期:
1)单列Singleton
services.AddSingleton<IOperation, Operation>();
2)范围Scoped
services.AddScoped<ILoginService, EFLoginService>()
var provider = services.BuildServiceProvider();
//创建范围
using (var scope1 = provider.CreateScope())
{
}
3)瞬态Tranisent
services.AddTransient<IOperationTransient, Operation>();
IServiceProvider 的常用服务定位器方法:
T GetService<T>() :如果获取不到对象,返回null。
T GetRequiredService<T>() :如果获取不到对象,则抛异常。
IEnumerable<T> GetServices<T>() :适用于肯恩有很多满足条件的服务。
3.应用
简单的邮件发送:
class Program
{
static void Main(string[] args)
{
//容器
ServiceCollection services = new ServiceCollection();
////多实现
//services.AddScoped<IConfigService, ConfigService>();
services.AddScoped(typeof(IConfigService),s=>new IniConfigService {FilePath="Mail.ini" });
//services.AddScoped<ILogProvider, LogProvider>();
////直接使用扩展方法
services.AddLog();
services.AddScoped<IMailService, MailService>();
using(var provider=services.BuildServiceProvider())
{
//服务定位器
var service = provider.GetRequiredService<IMailService>();
service.Send("111","222","你好");
}
}
}
配置文件mail.ini:
配置Lib:
namespace ConfigServices
{
public interface IConfigService
{
public string GetValue(string name);
}
//实现类1
public class IniConfigService : IConfigService
{
public string FilePath { get; set; }
public string GetValue(string name)
{
var kv=File.ReadAllLines(FilePath).Select(s => s.Split("=")).
Select(strs => new { Name = strs[0], Value = strs[1] }).
SingleOrDefault(s=>s.Name==name);
if (kv != null)
return kv.Value;
else
return null;
}
}
//实现类2
public class ConfigService : IConfigService
{
public string GetValue(string name)
{
return Environment.GetEnvironmentVariable(name);
}
}
}
日志Lib:
namespace LogService
{
public interface ILogProvider
{
public void LogInfo(string msg);
}
public class LogProvider : ILogProvider
{
public void LogInfo(string msg)
{
Console.WriteLine(msg);
}
}
}
//也可以提供扩展方法,方便框架使用者使用
namespace Microsoft.Extensions.DependencyInjection
{
public static class DIExtensions
{
public static void AddScoped(this IServiceCollection services)
{
services.AddScoped<ILogProvider, LogProvider>();
}
}
}
邮件Lib:
namespace MailServices
{
public interface IMailService
{
public void Send(string from, string to, string body);
}
public class MailService : IMailService
{
private readonly ILogProvider logProvider;
private readonly IConfigService configService;
//DI自动注入
public MailService(ILogProvider logProvider, IConfigService configService)
{
this.logProvider = logProvider;
this.configService = configService;
}
public void Send(string from, string to, string body)
{
logProvider.LogInfo("开始。。。");
Console.WriteLine($"服务:{configService.GetValue("ServerName")}," +
$"端口:{configService.GetValue("Port")}");
Console.WriteLine($"{from}->{to}:{body}");
logProvider.LogInfo("结束。。。");
}
}
}
执行结果:
4.可覆盖的配置读取器
Main函数:
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<IConfigService, ConfigService>();
services.AddScoped(typeof(IConfigService),s=>new IniConfigService {FilePath="Mail.ini" });
services.AddScoped<IConfigReader, LayerddConfigReader>();
services.AddScoped<ILogProvider, LogProvider>();
services.AddScoped<IMailService, MailService>();
using(var provider=services.BuildServiceProvider())
{
var service = provider.GetRequiredService<IMailService>();
service.Send("111","222","你好");
}
}
配置:
读取器Lib:
namespace ConfigServices
{
public interface IConfigReader
{
public string GetValue(string name);
}
public class LayerddConfigReader : IConfigReader
{
private readonly IEnumerable<IConfigService> services;
public LayerddConfigReader(IEnumerable<IConfigService> services)
{
this.services = services;
}
public string GetValue(string name)
{
string value = null;
foreach(var v in services)
{
string newvalue = v.GetValue(name);
if (newvalue != null)
value = newvalue;
}
return value;
}
}
}
邮件Lib:
namespace MailServices
{
public interface IMailService
{
public void Send(string from, string to, string body);
}
public class MailService : IMailService
{
private readonly ILogProvider logProvider;
private readonly IConfigReader configService;
//DI自动注入
public MailService(ILogProvider logProvider, IConfigReader configService)
{
this.logProvider = logProvider;
this.configService = configService;
}
public void Send(string from, string to, string body)
{
logProvider.LogInfo("开始。。。");
Console.WriteLine($"服务:{configService.GetValue("ServerName")}," +
$"端口:{configService.GetValue("Port")}");
Console.WriteLine($"{from}->{to}:{body}");
logProvider.LogInfo("结束。。。");
}
}
}
执行结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!