依赖注入

发布时间 2024-01-11 22:01:01作者: 茜茜87

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("结束。。。");
        }
    }
}

 执行结果: