Activator.CreateInstance 抛出 MissingMethodException 是因目标类型无 public 无参构造函数;解决需显式传参、用 GetConstructor+Invoke 处理非 public 构造器,或预构造封闭泛型类型。

Activator.CreateInstance 为什么经常抛出 MissingMethodException
直接用 Activator.CreateInstance(Type) 创建实例时,如果目标类型没有无参构造函数,就会立刻报 MissingMethodException: No parameterless constructor defined for this object。这不是反射本身的问题,而是 .NET 强制要求:当不传参数时,它只找 public 无参构造器。
- 解决办法是显式传入参数,匹配目标类型的某个 public 构造函数签名,例如
Activator.CreateInstance(typeof(MyClass), "hello", 42) - 如果构造函数是 private 或 internal,
Activator默认不访问(即使加了[InternalsVisibleTo]也不行),必须换用Type.GetConstructor+ConstructorInfo.Invoke - 泛型类型需先用
typeof(GenericType).MakeGenericType(...)构造封闭类型,再传给CreateInstance,否则会因类型未闭合而失败
比 Activator.CreateInstance 更快的替代方案有哪些
在高频创建场景(如 ORM 实体映射、JSON 反序列化内部逻辑)中,Activator.CreateInstance 因每次调用都做构造器查找+权限检查,性能明显低于缓存后的委托调用。
- 推荐用
Expression.Lambda编译构造委托:Expression.New(type.GetConstructor(types)).Compile(),首次稍慢,后续调用接近 new 操作符开销 - .NET 5+ 可考虑
System.Runtime.CompilerServices.Unsafe.CreateInstance<t>()</t>,但它跳过构造函数执行(只分配内存并初始化字段为默认值),仅适用于无副作用、无初始化逻辑的 POCO - 避免在循环内反复调用
Activator.CreateInstance(Type)—— 提前缓存Type对象和构造器信息,或封装成工厂委托
如何用 Activator 处理带 ref/out 参数的构造函数
Activator.CreateInstance 的所有重载都不支持 ref/out 参数传递 —— 它底层调用的是 ConstructorInfo.Invoke,而后者明确要求传入的参数数组元素必须是“按值传递”的实际值。
- 如果你看到类似
ref int x = ...; CreateInstance(typeof(T), x)的写法,编译就通不过;运行时也无法绕过该限制 - 真实需求往往来自 COM 互操作或极少数遗留设计,此时应放弃
Activator,改用ConstructorInfo.Invoke并手动构造object[],其中 ref/out 参数对应位置填null(由被调用方在内部处理),但前提是该构造函数确实被标记为[PreserveSig]或通过 COM Callable Wrapper 暴露 - 绝大多数 C# 类型根本不该有 ref/out 构造参数,这是设计信号:该类型不适合用反射创建
Activator.CreateInstance 和 FormatterServices.GetUninitializedObject 的本质区别
两者都能得到一个对象实例,但语义完全不同:Activator.CreateInstance 执行构造函数逻辑(包括字段初始化、base 调用、this(...) 链等),而 FormatterServices.GetUninitializedObject 直接分配内存并把所有字段置为 default(T),完全跳过任何构造器。
- 反序列化框架(如 BinaryFormatter 已废弃,但某些自定义协议还在用)依赖后者实现“无构造重建”,避免构造器中对外部资源的依赖导致失败
- 使用
GetUninitializedObject后,若类型含非空引用字段(如string name;),其值就是null,不是你代码里写的= "unknown"—— 字段初始值表达式被彻底忽略 - 它不检查构造器可访问性,也不触发任何静态构造器(
static Type()),所以线程安全性和副作用行为与常规 new 完全不同
别为了“省一次构造函数调用”就随意用 GetUninitializedObject —— 除非你清楚自己在重建序列化上下文,且能承担字段未初始化的风险。


















