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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步