c# ioc 容器有哪些

.NET主流IOC容器有4个:Microsoft.Extensions.DependencyInjection(官方内置,轻量但功能有限)、Autofac(最成熟第三方,支持高级生命周期和模块化注册)、Unity与Ninject(已停止维护,仅适用于遗留项目)。

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() 等扩展方法
  • Program.cs 中通过 host.Services.GetService() 解析
  • 只支持三种生命周期:AddSingletonAddScopedAddTransient —— 没有 InstancePerMatchingLifetimeScope 这类 Autofac 特性
  • 不能解析构造函数中带非注册参数的类型(比如 public Logger(string name) 会失败,除非显式配置)

Autofac 为什么仍是首选第三方容器?

当项目需要更精细的生命周期控制、模块化注册、属性注入、动态代理或与 ASP.NET Core 深度集成时,Autofac 是目前最成熟、文档最全、社区最活跃的替代方案。

  • 支持 InstancePerLifetimeScopeInstancePerMatchingLifetimeScope("admin")InstanceP

    erOwned()
    等高级作用域模式
  • 可按程序集、命名空间或自定义条件批量注册(RegisterAssemblyTypes
  • 能无缝替换 Microsoft 默认容器:只需在 Program.cs 调用 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
  • 注意:NuGet 包名是 Autofac.Extensions.DependencyInjection(用于集成),不是 Autofac 单独引用

Unity 和 Ninject 还能用吗?

不建议新项目使用。Unity 已于 2025 年由微软正式归档(archive),Ninject 自 2025 年起无实质更新,且两者对 .NET 6+ 的泛型主机(Generic Host)支持不完善,容易在 Host.CreateApplicationBuilder 场景下报 InvalidOperationException: No service for type '...' has been registered

  • 如果你正在维护老 WPF 或 .NET Framework 4.x 项目,它们仍可工作
  • 迁移到新项目时,遇到 Resolve() 报错或构造函数注入失败,大概率是容器未正确接管 Host 生命周期
  • Unity 的 RegisterType().As() 语法看似简洁,但调试依赖树非常困难 —— 缺少像 Autofac 的 Resolve>() 这种开箱即用的集合解析能力

自己写一个简易 IOC 容器靠谱吗?

仅限学习或极简脚本场景。用 Dictionary + Activator.CreateInstance 实现注册/解析,确实几小时就能跑通,但很快会撞墙:

  • 无法处理循环依赖(一调用就栈溢出)
  • 不支持泛型注册(Register>() 会失败)
  • 生命周期完全靠手动 new / Dispose 管理,没有作用域自动释放机制
  • 没有线程安全保障 —— 多次并发 GetService 可能创建重复单例
private readonly Dictionary _mappings = new();
public void Register() where TImplementation : class, TService
{
    _mappings[typeof(TService)] = typeof(TImplementation);
}
public TService GetService()
{
    var implType = _mappings[typeof(TService)];
    return (TService)Activator.CreateInstance(implType);
}

真正卡住人的从来不是“选哪个容器”,而是什么时候该用作用域、什么时候必须用单例、以及如何让 Worker Service 或中间件里的对象也参与 DI 生命周期——这些细节,比容器名字重要得多。