activatorutilities.createfactory 返回 objectfactory 委托,需配合 iserviceprovider 才能解析依赖并实例化,不支持生命周期管理或自动释放;它为 di 容器底层生成高效工厂,非替代 activator.createinstance 的通用创建方法。

ActivatorUtilities.CreateFactory 不是用来直接创建实例的,它返回的是一个 ObjectFactory 委托,必须配合 IServiceProvider 才能完成依赖解析和实例化。直接调用它不会触发 DI 容器的生命周期管理或服务解析逻辑。
为什么不能用 ActivatorUtilities.CreateFactory 直接 new 实例
这个方法设计初衷不是替代 Activator.CreateInstance,而是为 DI 容器底层(比如 ASP.NET Core 的 ServiceProvider)生成高效、可复用的工厂函数。它本身不持有服务提供者,也不执行构造函数参数注入。
-
ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(ILogger) })只生成一个委托,形如(serviceProvider, arguments) => new MyService(serviceProvider.GetRequiredService<ilogger>())</ilogger> - 若你传入
null作为IServiceProvider,且构造函数依赖ILogger,运行时会抛出InvalidOperationException:“No service for type 'ILogger' has been registered” - 它不处理 transient/scoped/singleton 生命周期,也不会调用
IDisposable.Dispose()—— 这些都由容器在GetService或CreateScope后统一管理
正确用法:配合 IServiceProvider 构造实例
典型场景是手动在某个作用域内按需创建带 DI 依赖的对象(比如在中间件、过滤器或非托管上下文中临时构建服务)。
- 先获取当前作用域的
IServiceProvider(例如从HttpContext.RequestServices或IServiceScope.ServiceProvider) - 用
ActivatorUtilities.CreateFactory预编译工厂(建议缓存,避免重复编译开销) - 调用工厂委托,传入 provider 和可选的显式参数(用于覆盖 DI 解析,如
new object[] { "override-value" })
示例:
var factory = ActivatorUtilities.CreateFactory(typeof(EmailSender), new[] { typeof(IEmailTemplateService) });
// 在某个 scope 内
using var scope = serviceProvider.CreateScope();
var instance = (EmailSender)factory(scope.ServiceProvider, new object[] { null }); // null 表示让 DI 提供 IEmailTemplateService
和 Activator.CreateInstance 的关键区别在哪
两者根本不在同一抽象层:
-
Activator.CreateInstance(typeof(MyClass), args)是纯反射调用,绕过 DI,参数必须完全匹配构造函数签名,不支持接口注入 -
ActivatorUtilities.CreateFactory是 DI 感知的,能自动解析IServiceProvider中注册的服务,但要求类型构造函数参数要么是已注册服务,要么显式传入(且类型要严格一致) - 性能上,
CreateFactory编译一次后调用极快;而反复调用Activator.CreateInstance有明显反射开销 - 如果你只是想动态加载一个无依赖的插件类(如
typeof(IReportGenerator)来自外部 DLL),用Activator.CreateInstance更直接;如果该类依赖ILogger、IConfiguration等,就必须走ActivatorUtilities+IServiceProvider
容易踩的坑:参数类型不匹配和生命周期错位
这是最常导致 InvalidCastException 或空引用的地方:
- 显式传参时,数组元素类型必须和构造函数参数声明类型**完全一致**,
int不能代替int?,string不能代替IOptions<myconfig></myconfig> - 不要在 singleton service 中捕获 scoped service(如
HttpContext),否则引发“Cannot resolve scoped service from root provider”错误 - 工厂委托返回的对象**不由容器跟踪**,即使类型实现了
IDisposable,也不会被自动释放 —— 必须手动调用Dispose()或用using
真正复杂的地方在于:你得清楚自己是在用 DI 容器的规则做事,还是在做裸反射。混用两者(比如用 CreateFactory 却传入手工 new 的依赖)会破坏容器契约,问题往往延迟到 Dispose 阶段才暴露。











