Activator 是 C# 中用于动态创建对象实例 的核心类,位于 System 命名空间。它通过**反射(Reflection)**机制,在运行时根据类型信息创建对象,而无需在编译时知道具体类型。
🔍 一、Activator 的核心作用
- 在不知道具体类型的情况下创建实例(如 IoC 容器、插件系统、序列化框架等)。
- 支持带参数 或无参的构造函数调用。
- 可创建值类型 和引用类型。
- 是依赖注入(DI)、ORM、MVC 框架等底层常用工具。
🧱 二、常用方法详解
1. Activator.CreateInstance(Type type)
调用类型的无参构造函数创建实例。
csharp
Type type = typeof(List<string>);
object instance = Activator.CreateInstance(type);
// 等价于:new List<string>();
✅ 要求:类型必须有 public 无参构造函数 ,否则抛出 MissingMethodException。
2. Activator.CreateInstance(Type type, params object[] args)
调用匹配参数的构造函数创建实例。
csharp
Type type = typeof(Dictionary<string, int>);
object dict = Activator.CreateInstance(type, 10); // 调用 Dictionary(int capacity)
🔍 匹配规则:
- 按参数数量和类型精确匹配 (不支持隐式转换,如
int→long会失败)。 - 如果多个构造函数匹配,行为未定义(通常选第一个,但不可靠)。
⚠️ 注意:参数必须按构造函数声明顺序传入。
3. 泛型版本:Activator.CreateInstance<T>()
编译时已知类型,但仍用反射创建(性能略低于
new T())。
csharp
List<string> list = Activator.CreateInstance<List<string>>();
✅ 要求:T 必须有 public 无参构造函数 (受 where T : new() 约束)。
4. 创建非 public 或内部类型(需 BindingFlags)
csharp
// 假设 MyClass 有一个 internal 构造函数
Type type = typeof(MyClass);
var instance = Activator.CreateInstance(
type,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new object[] { "param" },
null
);
适用于测试私有构造函数或访问内部类型(需注意安全性)。
5. 创建数组、委托、指针等特殊类型
csharp
// 创建长度为 5 的 string 数组
Array arr = (Array)Activator.CreateInstance(typeof(string[]), 5);
// 创建多维数组
Array matrix = Array.CreateInstance(typeof(int), 3, 4); // 更推荐用 Array.CreateInstance
⚙️ 三、底层原理(简要)
Activator.CreateInstance 内部使用:
- 反射 (
ConstructorInfo.Invoke) - 在 .NET Core / .NET 5+ 中,对常见场景做了优化(如缓存委托)
- 但仍比
new慢 10~100 倍(见下文性能)
🚀 四、性能问题与替代方案
❌ Activator.CreateInstance 性能较差
- 每次调用都涉及反射、参数校验、安全检查。
- 不适合高频调用(如循环内)。
✅ 高性能替代方案
方案 1:使用 System.Linq.Expressions 编译表达式树
csharp
var constructor = typeof(MyClass).GetConstructor(new Type[] { typeof(string) });
var param = Expression.Parameter(typeof(object[]));
var argsExp = constructor.GetParameters().Select((p, i) =>
Expression.Convert(Expression.ArrayIndex(param, Expression.Constant(i)), p.ParameterType)
).ToArray();
var newExp = Expression.New(constructor, argsExp);
var lambda = Expression.Lambda<Func<object[], object>>(newExp, param);
var factory = lambda.Compile();
// 使用
object instance = factory(new object[] { "hello" });
方案 2:使用 System.Reflection.Emit(更复杂,性能最高)
适用于框架开发(如 DI 容器)。
方案 3:.NET 7+ 推荐:RuntimeHelpers.GetUninitializedObject(仅限无参、跳过构造函数)
csharp
object obj = RuntimeHelpers.GetUninitializedObject(typeof(MyClass));
// ⚠️ 危险!不调用构造函数,字段为默认值
方案 4:泛型约束 + new()
csharp
public T CreateInstance<T>() where T : new()
{
return new T(); // 零反射,最快!
}
🛑 五、常见陷阱与注意事项
| 问题 | 说明 |
|---|---|
| 无参构造函数缺失 | 抛出 MissingMethodException |
| 参数类型不匹配 | 抛出 ArgumentException |
| 私有构造函数 | 默认无法调用,需 BindingFlags.NonPublic |
| 值类型处理 | Activator.CreateInstance(typeof(int)) 返回 0(合法) |
| 抽象类/接口 | 不能直接创建,会抛异常 |
| 线程安全 | CreateInstance 本身线程安全,但创建的对象不一定 |
✅ 六、典型应用场景
-
IoC/DI 容器
csharpobject instance = Activator.CreateInstance(implementationType, dependencies); -
插件系统(加载外部 DLL)
csharpAssembly asm = Assembly.LoadFrom("Plugin.dll"); Type pluginType = asm.GetType("MyPlugin"); IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); -
ORM 实体实例化
(如 Entity Framework 动态创建实体对象)
-
单元测试中 Mock 对象创建
-
泛型工厂模式
csharppublic T Create<T>() => Activator.CreateInstance<T>();
📌 总结
| 特性 | 说明 |
|---|---|
| 用途 | 运行时动态创建对象 |
| 核心方法 | CreateInstance(Type, args) |
| 优点 | 灵活,支持任意类型 |
| 缺点 | 性能低,易出错 |
| 最佳实践 | 仅用于低频场景;高频场景用表达式树或泛型约束 |
💡 建议 :在写 DI 容器、框架或插件系统时,初期可用
Activator快速验证逻辑,后期替换为高性能方案。