依赖注入概要
C#依赖注入核心(传染性):构造注入+拿来即用
举个例子,假设你开发过程需要日志记录或者邮件短信发送或者相关的通用组件。
1.可以先自定义一个接口,然后实现接口mock一下(例如控制台输出一下:XX操作成功),
2.通过依赖注入直接使用,继续完成主要功能逻辑后。
3.在主要逻辑完成后。再回过头来重新实现指定以接口。在注入的地方将Mock注入替换成实际功能
好处:不需要在主流程中修改代码(Aop)
来看两个例子:
例子1:流水线,流水账
using System.Data; DataTable SearchSql(string user,string sql) { try { Console.WriteLine($"执行Sql"); //执行SQL string message = $"{user}执行了sql查询,SQL语句:{sql}"; LogToFile(message);//记录日志 SendMessage("管理员", message);//发送邮件 } catch (Exception e) { Console.WriteLine(e.Message); } return null; } void LogToFile(string message) => Console.WriteLine($"记录日志:{message}"); void SendMessage(string manager, string message) => Console.WriteLine($"发送给{manager}的信息:{message}");
再来看例子二:
using System.Data; class Business { private readonly ILog _log; private readonly ISendMessage _sendMessage; public Business(ILog log, ISendMessage sendMessage) { _log = log; _sendMessage = sendMessage; } public DataTable SearchSql(string user, string sql) { Console.WriteLine($"执行Sql"); //执行SQL string message = $"{user}执行了sql查询,SQL语句:{sql}"; _log.Log(message); _sendMessage.Send("管理员", message); return null; } } public interface ILog { public void Log(string message); } class LogToDatabase : ILog { public void Log(string message) { Console.WriteLine("写入数据库:" + DateTime.Now.ToString() + message); } } class LogToFile : ILog { public void Log(string message) { Console.WriteLine("写入文件:"+DateTime.Now.ToString()+ message); } } public interface ISendMessage { public void Send(string id, string message); } class SendWeChat : ISendMessage//发送微信 { public void Send(string id, string message) { Console.WriteLine($"发送微信:{message}给{id}"); } } class SendEmail : ISendMessage//发送邮件 { public void Send(string id, string message) { Console.WriteLine($"发送邮件:{message}给{id}"); } } class SendTextMessage : ISendMessage//发送短信 { public void Send(string id, string message) { Console.WriteLine($"发送短信:{message}给{id}"); } }
重点:例子二 可以自由切换各类消息发送,也可以自由切换各种日志记录。反观例子1,必须修改主要流程。
依赖注入使用:
项目结构:
Config库:
namespace Microsoft.Extensions.DependencyInjection
{
public static class ConfigService
{
public static void AddConfigService(this ServiceCollection serviceCollection)
{
serviceCollection.AddScoped
}
}
}
public interface IConfig { public string GetConfigration(string key); } public class Connection : IConfig { private readonly ILog _log; public Dictionary<string, string> _config; public Connection(ILog log) { _config = new Dictionary<string, string>() { {"MySql","MySql:xxxxxxxxxxx" }, {"Oracle","Oracle:xxxxxxxxxxx" }, {"DB2","DB2:xxxxxxxxxxx" }, {"SqlServrce","SqlServrce:xxxxxxxxxxx" } }; _log = log; } public string GetConfigration(string key) { _log.DebugLog($"获取Key={key}的值"); return _config[key]; } }
Log库:
public interface ILog { public void DebugLog(string message); public void ErrorLog(string message); } public class Logger : ILog { public void DebugLog(string message) { Console.WriteLine("DeBug:" + message); } public void ErrorLog(string message) { Console.WriteLine("Error:" + message); } }
控制台:
internal class Controller { private readonly IConfig _config; private readonly ILog _log; public Controller(IConfig config, ILog log) { _config = config; _log = log; } public DataTable SearchSql(string sql) { try { string conn= _config.GetConfigration("MySql"); Console.WriteLine($"Controller得到值:{conn}"); } catch (Exception e) { Console.WriteLine(e.Message); } return null; } }
using ConfigService; using LogService; using Microsoft.Extensions.DependencyInjection; using 依赖注入; ServiceCollection sc=new ServiceCollection(); sc.AddScoped(); //sc.AddScoped ();
sc.AddConfigService(); //扩展方法 方式(可以不需要引用库) sc.AddScoped(); using (ServiceProvider sp = sc.BuildServiceProvider()) { var controle= sp.GetRequiredService (); controle.SearchSql("select"); }
输出结果: