console.log(🍺|

今晚打老虎!

园龄:5年1个月粉丝:39关注:9

Autofac:在 .NET 中实现依赖注入

大家好,我是深山踏红叶,今天我们来聊一聊Autofac 依赖注入框架,它是一个开源的并且提供了多种注入方式,并提供了对生命周期管理和作用域控制的强大支持。

引言

依赖注入(Dependency Injection,简称 DI)是一种重要的设计模式,旨在减少类与类之间的依赖关系。Autofac 是一个广泛使用的 .NET 依赖注入容器,提供了强大的功能和灵活的配置选项,帮助开发人员有效地管理对象的生命周期和依赖关系。

什么是依赖注入(DI)?

定义

依赖注入是一种设计模式,通过外部容器来注入所需的依赖对象,从而使得类不再自己创建所依赖的对象。

使用原因

  • 降低耦合:使类与类之间的依赖关系更加灵活,降低了耦合性。
  • 易于测试:提供 mock 对象,方便单元测试。
  • 提高可维护性:集中管理依赖,便于修改和扩展。

Autofac 与微软自带的 DI

选择Autofac而不是微软自带的依赖注入框架,主要是因为Autofac功能更强大,支持更复杂的依赖管理和高级特性,适合复杂项目。而微软自带的依赖注入框架更简单、轻量级,适合普通场景。

Autofac:支持条件注入、属性注入、模块化注册、自动扫描、按约定注册等高级特性。
Autofac:提供了丰富的扩展机制,例如通过 Module 批量注册服务,或实现自定义 IServiceProvider。

微软自带依赖注入框架:功能较为基础,主要支持 Transient、Scoped 和 Singleton 生命周期管理,缺乏高级特性。
微软自带依赖注入框架:扩展性较弱,对于复杂的应用场景可能不够灵活

安装

第一步,老规矩,先安装

Install-Package Autofac

使用

定义接口和实现类

定义接口 IGreeter 及其实现类 Greeter

public interface ICar
{
    void Drive();
}

public class Car : ICar
{
    public void Drive()
    {
        Console.WriteLine(NA+"Driving a car.");
    }
}

基本的使用

using Autofac;
using AutofacDemo;
//创建容器
var builder = new ContainerBuilder();
builder.RegisterType<Car>().As<ICar>();  // 注册 Car 类实现 ICar 接口
var container = builder.Build();  // 构建容器 
var car = container.Resolve<ICar>();  // 解析 ICar 实现
car.Drive();

注册方式

类型注册 (Type Registration)

通过类型注册,可以将接口类型与实现类型关联,使得当解析该接口时,容器会返回实现类型的实例。

var builder = new ContainerBuilder();
builder.RegisterType<Car>().As<ICar>();  // 注册 Car 类型为 ICar 类型
var container = builder.Build();

var car = container.Resolve<ICar>();  // 解析 ICar 类型,返回 Car 实例

实例注册 (Instance Registration)

通过实例注册,可以直接将一个已有的对象实例注册到容器中,而不是让容器创建一个新的实例。

var car = new Car();
var builder = new ContainerBuilder();
builder.RegisterInstance(car).As<ICar>();  // 将已有的 car 实例注册为 ICar 类型
var container = builder.Build();

var resolvedCar = container.Resolve<ICar>();  // 返回注册的 car 实例

使用工厂方法注册 (Factory Registration)

允许通过工厂方法注册类型。

var builder = new ContainerBuilder();
builder.Register(c => new Car()).As<ICar>();  // 使用工厂方法注册 Car 类型为 ICar 类型
var container = builder.Build();

var car = container.Resolve<ICar>();  // 通过工厂方法解析 Car 实例

单例注册 (Single Instance Registration)

将类型注册为单例,在整个容器生命周期内只创建一个实例。

var builder = new ContainerBuilder();
builder.RegisterType<Car>().As<ICar>().SingleInstance();  // 注册为单例
var container = builder.Build();

var car1 = container.Resolve<ICar>();
var car2 = container.Resolve<ICar>();

Console.WriteLine(ReferenceEquals(car1, car2));  // 输出:True,表示 car1 和 car2 是同一个实例

作用域注册 (Instance Per Lifetime Scope)

在每个生命周期作用域内都使用相同的实例,使用 InstancePerLifetimeScope 注册。

var builder = new ContainerBuilder();
builder.RegisterType<Car>().As<ICar>().InstancePerLifetimeScope();  // 在生命周期作用域内共享实例
var container = builder.Build();

using (var scope = container.BeginLifetimeScope())
{
    var car1 = scope.Resolve<ICar>();
    var car2 = scope.Resolve<ICar>();
    Console.WriteLine(ReferenceEquals(car1, car2));  // 输出:True,表示 car1 和 car2 是同一个实例
}

using (var scope = container.BeginLifetimeScope())
{
    var car3 = scope.Resolve<ICar>();
    Console.WriteLine(ReferenceEquals(car1, car3));  // 输出:False,表示 car1 和 car3 是不同的实例
}

开放泛型注册 (Open Generic Registration)

支持泛型类型的注册,允许注册并解析具有泛型类型参数的服务。

public interface IRepository<T> { void Add(T item); }
public class Repository<T> : IRepository<T> { public void Add(T item) { Console.WriteLine("Item added"); } }

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));  // 注册开放泛型类型
var container = builder.Build();

var customerRepository = container.Resolve<IRepository<Customer>>();  // 解析为 Repository<Customer>
customerRepository.Add(new Customer());  // 输出:Item added

命名注册 (Named Registration)

在某些情况下,可能需要为同一类型注册多个实例。Autofac 支持通过命名来解决这个问题,可以为每个实例指定一个名称。

public interface ICar { void Drive(); }
public class SportsCar : ICar { public void Drive() { Console.WriteLine("Driving a sports car."); } }
public class FamilyCar : ICar { public void Drive() { Console.WriteLine("Driving a family car."); } }

var builder = new ContainerBuilder();
builder.RegisterType<SportsCar>().Named<ICar>("SportsCar");  // 注册 SportsCar 类型为命名的 ICar
builder.RegisterType<FamilyCar>().Named<ICar>("FamilyCar");  // 注册 FamilyCar 类型为命名的 ICar
var container = builder.Build();

var sportsCar = container.ResolveNamed<ICar>("SportsCar");
sportsCar.Drive();  // 输出:Driving a sports car.

var familyCar = container.ResolveNamed<ICar>("FamilyCar");
familyCar.Drive();  // 输出:Driving a family car.

键控注册 (Keyed Registration)

键控注册是类似于命名注册,它通过指定一个键来区分多个类型实例,而不是使用字符串名称。可以使用任何对象作为键。

public interface ICar { void Drive(); }
public class SportsCar : ICar { public void Drive() { Console.WriteLine("Driving a sports car."); } }
public class FamilyCar : ICar { public void Drive() { Console.WriteLine("Driving a family car."); } }

var builder = new ContainerBuilder();
builder.RegisterType<SportsCar>().Keyed<ICar>("sports");  // 注册 SportsCar 类型为键 "sports"
builder.RegisterType<FamilyCar>().Keyed<ICar>("family");  // 注册 FamilyCar 类型为键 "family"
var container = builder.Build();

var sportsCar = container.ResolveKeyed<ICar>("sports");
sportsCar.Drive();  // 输出:Driving a sports car.

var familyCar = container.ResolveKeyed<ICar>("family");
familyCar.Drive();  // 输出:Driving a family car.

注入方式

  • 构造函数注入:通过构造函数来传递依赖。推荐使用的方式,能够明确展示依赖关系。
  • 属性注入:通过公共属性来注入依赖。适用于依赖不是必须的场景。
  • 方法注入:通过方法参数注入依赖。适用于一些临时的依赖注入,或者在某些情况下依赖关系不稳定时使用。
public class Service
{
    private readonly IGreeter _greeter;

    public Service(IGreeter greeter)
    {
        _greeter = greeter;
    }

    public void Serve()
    {
        _greeter.Greet("Service");
    }
}

builder.RegisterType<Greeter>().As<IGreeter>();
builder.RegisterType<Service>();

var service = container.Resolve<Service>();
service.Serve();
  • 构造函数注入是最常见的依赖注入方式

生命周期管理

//单例: 只有一个实例被创建
builder.RegisterType<Car>().As<ICar>().SingleInstance();
//瞬时: 每次解析都会创建一个新的实例。
builder.RegisterType<Car>().As<ICar>().InstancePerDependency();
//作用域: 在一个范围内共享实例。
var scope = container.BeginLifetimeScope();

高级功能

模块化注册

模块化注册有助于更好地组织和管理依赖:

public class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<Greeter>().As<IGreeter>();
    }
}

var builder = new ContainerBuilder();
builder.RegisterModule(new MyModule());

Assembly 扫描

Autofac 提供了扫描程序集并自动注册类型的功能。可以自动识别符合特定条件的类型,并注册为服务。

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
           .Where(t => t.Name.EndsWith("Service"))
           .AsImplementedInterfaces();

总结

Autofac 是 .NET 平台中最流行和功能强大的依赖注入容器之一。通过 Autofac,可以更灵活地管理依赖关系,减少类之间的耦合度,提升代码的可测试性和可维护性。更多详细信息请参考官方文档
欢迎关注我的公众号“Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节

本文作者:今晚打老虎!

本文链接:https://www.cnblogs.com/netcore5/p/18740229

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   今晚打老虎!  阅读(53)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起