C# 中主流、生产可用的 IOC 容器有 4 个核心选择:Microsoft.Extensions.DependencyInjection(官方内置)、Autofac、Unity、Ninject。其中前两个是当前最推荐的,后两个已基本停止活跃维护或仅用于遗留项目。
Microsoft.Extensions.DependencyInjection 是什么?怎么用?
这是 .NET Core 2.0+ 及所有现代 .NET(5/6/7/8/9)默认集成的轻量级 DI 容器,不是第三方库,而是 SDK 自带。它不支持高级生命周期(如作用域嵌套、命名作用域),但足够支撑绝大多数 Web API、Worker Service 和控制台应用。
注册服务只需调用builder.Services.AddSingleton<irepository sqlrepository>()</irepository>等扩展方法 在
Program.cs中通过
host.Services.GetService<irepository>()</irepository>解析 只支持三种生命周期:
AddSingleton、
AddScoped、
AddTransient—— 没有
InstancePerMatchingLifetimeScope这类 Autofac 特性 不能解析构造函数中带非注册参数的类型(比如
public Logger(string name)会失败,除非显式配置)
Autofac 为什么仍是首选第三方容器?
当项目需要更精细的生命周期控制、模块化注册、属性注入、动态代理或与 ASP.NET Core 深度集成时,Autofac 是目前最成熟、文档最全、社区最活跃的替代方案。
支持InstancePerLifetimeScope、
InstancePerMatchingLifetimeScope("admin")、InstancePerOwned<t>()</t>等高级作用域模式 可按程序集、命名空间或自定义条件批量注册(
RegisterAssemblyTypes) 能无缝替换 Microsoft 默认容器:只需在
Program.cs调用
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())注意:NuGet 包名是
Autofac.Extensions.DependencyInjection(用于集成),不是
Autofac单独引用
Unity 和 Ninject 还能用吗?
不建议新项目使用。Unity 已于 2021 年由微软正式归档(archive),Ninject 自 2020 年起无实质更新,且两者对 .NET 6+ 的泛型主机(Generic Host)支持不完善,容易在
Host.CreateApplicationBuilder场景下报
InvalidOperationException: No service for type '...' has been registered。 如果你正在维护老 WPF 或 .NET Framework 4.x 项目,它们仍可工作 迁移到新项目时,遇到
Resolve<t>()</t>报错或构造函数注入失败,大概率是容器未正确接管 Host 生命周期 Unity 的
RegisterType<t>().As<i>()</i></t>语法看似简洁,但调试依赖树非常困难 —— 缺少像 Autofac 的
Resolve<ienumerable>>()</ienumerable>这种开箱即用的集合解析能力
自己写一个简易 IOC 容器靠谱吗?
仅限学习或极简脚本场景。用
Dictionary<type type></type>+
Activator.CreateInstance实现注册/解析,确实几小时就能跑通,但很快会撞墙: 无法处理循环依赖(一调用就栈溢出) 不支持泛型注册(
Register<irepository>>()</irepository>会失败) 生命周期完全靠手动
new/
Dispose管理,没有作用域自动释放机制 没有线程安全保障 —— 多次并发
GetService可能创建重复单例
private readonly Dictionary<Type, Type> _mappings = new();
public void Register<TService, TImplementation>() where TImplementation : class, TService
{
_mappings[typeof(TService)] = typeof(TImplementation);
}
public TService GetService<TService>()
{
var implType = _mappings[typeof(TService)];
return (TService)Activator.CreateInstance(implType);
}真正卡住人的从来不是“选哪个容器”,而是什么时候该用作用域、什么时候必须用单例、以及如何让 Worker Service 或中间件里的对象也参与 DI 生命周期——这些细节,比容器名字重要得多。
