在.NET的依赖注入体系中,基础的IServiceProvider只能解析容器中已注册的服务类型,如果某个类型的构造函数包含未在容器中注册的参数,直接使用GetService方法会返回null或者抛出异常。ActivatorUtilities类提供了补充能力,能够利用容器中已注册的服务,自动填充构造函数的已注册参数,未注册的参数则由开发者手动传入,从而实现复杂对象的动态创建。

ActivatorUtilities核心方法介绍
ActivatorUtilities主要包含两个常用的静态方法,分别适用于不同的创建场景:
- CreateInstance:用于创建指定类型的实例,构造函数的参数中,已在容器中注册的类型会自动从容器解析,未注册的参数需要开发者按顺序传入。
- GetServiceOrCreateInstance:尝试从容器中获取指定类型的实例,如果容器中未注册该类型,则自动使用ActivatorUtilities创建实例,同样支持混合构造参数。
基础使用示例
首先我们定义几个基础的服务类型,模拟实际的业务场景:
// 已在容器中注册的服务
public interface ILogService
{
void Log(string message);
}
public class ConsoleLogService : ILogService
{
public void Log(string message)
{
Console.WriteLine($"日志内容:{message}");
}
}
// 需要创建实例的目标类型,构造函数包含已注册和未注册的参数
public class UserService
{
private readonly ILogService _logService;
private readonly string _userName;
private readonly int _userAge;
// ILogService已在容器中注册,string和int未在容器中注册
public UserService(ILogService logService, string userName, int userAge)
{
_logService = logService;
_userName = userName;
_userAge = userAge;
}
public void ShowUserInfo()
{
_logService.Log($"用户姓名:{_userName},年龄:{_userAge}");
}
}
接下来配置DI容器,注册ILogService服务,然后使用ActivatorUtilities创建UserService实例:
using Microsoft.Extensions.DependencyInjection;
using System;
class Program
{
static void Main()
{
// 创建DI容器并注册服务
IServiceCollection services = new ServiceCollection();
services.AddTransient<ILogService, ConsoleLogService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// 使用ActivatorUtilities.CreateInstance创建实例
// 第一个参数是IServiceProvider,第二个参数是目标类型,后续参数是未注册的构造参数,按顺序传入
UserService userService = ActivatorUtilities.CreateInstance<UserService>(serviceProvider, "张三", 25);
userService.ShowUserInfo();
// 使用GetServiceOrCreateInstance方法,如果未注册UserService则自动创建
// 注意该方法要求目标类型的构造函数参数要么全在容器中注册,要么未注册的参数有默认值
// 此处UserService有未注册参数,所以需要确保参数可自动填充,或者改用CreateInstance
// 下面演示无未注册参数的类型使用GetServiceOrCreateInstance
public class SimpleService
{
private readonly ILogService _logService;
public SimpleService(ILogService logService)
{
_logService = logService;
}
public void DoWork()
{
_logService.Log("执行简单任务");
}
}
SimpleService simpleService = ActivatorUtilities.GetServiceOrCreateInstance<SimpleService>(serviceProvider);
simpleService.DoWork();
}
}
实际应用场景
动态创建带运行时参数的服务实例
当某个服务的构造参数需要运行时才能确定数值,比如用户ID、配置路径等,这些参数不适合提前注册到DI容器中,此时可以使用ActivatorUtilities混合容器服务和运行时参数创建实例。
public class OrderService
{
private readonly ILogService _logService;
private readonly string _orderId;
public OrderService(ILogService logService, string orderId)
{
_logService = logService;
_orderId = orderId;
}
public void ProcessOrder()
{
_logService.Log($"处理订单,订单ID:{_orderId}");
}
}
// 运行时获取订单ID后创建实例
string currentOrderId = "ORD202405001";
OrderService orderService = ActivatorUtilities.CreateInstance<OrderService>(serviceProvider, currentOrderId);
orderService.ProcessOrder();
工厂模式中结合DI容器
在工厂模式中,工厂类需要创建多种不同类型的实例,这些实例的构造函数可能包含部分公共的已注册服务,使用ActivatorUtilities可以避免手动从容器中解析每个依赖,简化工厂的实现逻辑。
public interface IFactory
{
T Create<T>(params object[] args) where T : class;
}
public class ServiceFactory : IFactory
{
private readonly IServiceProvider _serviceProvider;
public ServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public T Create<T>(params object[] args) where T : class
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider, args);
}
}
// 使用工厂创建实例
IFactory factory = new ServiceFactory(serviceProvider);
UserService user = factory.Create<UserService>("李四", 30);
user.ShowUserInfo();
注意事项
- ActivatorUtilities只能解析公共的构造函数,如果目标类型只有私有构造函数,创建实例会失败。
- 如果目标类型有多个公共构造函数,ActivatorUtilities会选择参数最多的那个公共构造函数,如果多个构造函数参数数量相同,可能会抛出异常,建议目标类型只保留一个公共构造函数。
- 传入的未注册参数顺序需要和构造函数中未注册参数的声明顺序一致,否则会导致参数赋值错误。
- ActivatorUtilities创建实例时不会自动跟踪实例的生命周期,生命周期管理需要开发者自行处理,或者结合容器的生命周期配置使用。
总结
ActivatorUtilities是.NET DI容器的重要补充,解决了基础DI无法处理混合构造参数的对象创建问题,在动态实例创建、工厂模式、运行时参数注入等场景中非常实用。开发者只需要掌握CreateInstance和GetServiceOrCreateInstance两个方法的使用方式,就能应对大部分高级DI使用需求,让依赖注入的使用更加灵活高效。
ActivatorUtilitiesC#DI容器依赖注入修改时间:2026-06-19 10:45:27