3.1依赖注入

3.1依赖注入

控制反转

传统开发中,对象都是开发者创建组装,开发者必须了解各类的使用方法且某些类的耦合度较高,例如想把sql serve数据库改为MySql数据库则需要更改某些代码。

控制反转的目的是让框架完成对象的创建和组装。从“我创建对象”编程“我要对象”,实现控制反转主要有两种方式:

服务定位器

假设框架中有个ServiceLocator类,可以直接调用GetService方法便可以获得想要的对象。

IDbConnection con = ServiceLocator.GetService<IDbConnection>();

依赖注入

一个对象中需要包含其他类型的对象,则在创建该对象的时候,框架会自动创建所需类型的对象。

容器:负责提供对象的注册和获取功能的框架

服务:注册到容器中的对象

依赖注入的基本使用

声明周期:获取服务的时候是创建一个新对象还是用之前对象

  1. 瞬态(transient):每次请求都创建一个新对象。
  2. 范围(scoped):在给定范围内,多次请求共享一个对象;在不同范围内,服务每次被请求的时候返回不同对象。ASP.NET Core中,同一次http请求,不同的注入会获得同一对象。
  3. 单例(singleton):全局共享一个服务对象。

使用建议:

如果一个类无状态,建议设置为单例;否则,框架环境有范围控制,则周期设置为范围;使用瞬态周期时要尽可能在自范围中使用,否则容易造成内存泄漏。

不同服务之间具有依赖关系,A服务有一个B服务的属性,那么B的声明周期不能比A短

依赖注入框架中注册服务的时候,可以设定服务类型和实现类型,这两者可以不相同。例:

  • 服务和实现类型都是SqlConnection时,在获取SqlConnection服务时,会返回SqlConnection对象

  • 服务是IDbConnection接口类型,实现类型都是SqlConnection时,在获取IDbConnection接口服务时,会返回SqlConnection对象

服务定位器案例:
using Microsoft.Extensions.DependencyInjectiony;
    
  
public interface ITestService
{
    public string Name { get; set; }
    public void SayHi();
}

public class TestServiceImpl : ITestService
{
    public string Name { get; set; }
    public void SayHi()
    {
        Console.WriteLine($"Hi, I'm {Name}");
    }
}
//获取服务之前要先注册服务

ServiceCollection services = new ServiceCollection();//1.创建用于注册服务的容器
//AddTransient、AddScoped、和AddSingleton分别注册瞬态、范围、单例服务
services.AddTransient<TestServiceImpl>();//2.注册一个瞬时服务,注册的服务必须涵盖程序中所有的所需服务
//ServiceProvider服务定位器
using (ServiceProvider sp = services.BuildServiceProvider())//3.获取服务定位器
{
    //4.通过调用GetRequiredService方法获得对象
    TestServiceImpl testService = sp.GetRequiredService<TestServiceImpl>();
    testService.Name = "tom";
    testService.SayHi();
}
依赖注入案例

接口—要注册的服务

interface IUserBiz{public bool CheckLogin(string userName, string password);}
interface IUserDAO{public User? GetByUserName(string userName);}

实现类

class UserBiz : IUserBiz
{
    private readonly IUserDAO userDao;//所依赖的对象

    public UserBiz(IUserDAO userDao) //构造函数中要求容器中必须注入IUserDAO服务
    {
        this.userDao = userDao;
    }

    public bool CheckLogin(string userName, string password)
    {...
    }
}

class UserDAO: IUserDAO
{
    private readonly IDbConnection conn;//所依赖的对象

    public UserDAO(IDbConnection conn)//构造函数中要求容器中必须注入IDbConnection服务
    {
        this.conn = conn;
    }

    public User? GetByUserName(string userName)
    {...
    }
}
组装服务
ServiceCollection services = new ServiceCollection();//1.创建用于注册服务的容器
//2.注册的服务必须涵盖程序中所有的所需服务
//注册IDbConnection服务
services.AddScoped<IDbConnection>(sp => {
    string connStr = "Data Source=.;Initial Catalog=DI_DB;Integrated Security=true";
    var conn = new SqlConnection(connStr);
    conn.Open();
    return conn;
});
services.AddScoped<IUserDAO, UserDAO>();//2.1.上面指定需要注入IUserDAO服务,但是要用UserDAO类来实现
services.AddScoped<IUserBiz, UserBiz>();
using (ServiceProvider sp = services.BuildServiceProvider())//3.获取服务定位器
{
    var userBiz = sp.GetRequiredService<IUserBiz>();
    bool b = userBiz.CheckLogin("yzk", "123456");
    Console.WriteLine(b);
}

依赖注入的传染性:一个对象是通过依赖注入创建的,那么这个类的构造函数中所有的参数都是依赖注入赋值。但是如果一个类是手动创建,那么构造函数中所有的参数不是依赖注入。所以一旦使用依赖注入,则应避免使用new来创建。

如果一个服务有多个实现对象,可以被参数声明为IEnumerable<T>类型

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步、步、为营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值