反射创建对象的关键难点是类型安全、构造器匹配和参数绑定;最稳妥方式是用Activator.CreateInstance调用public无参构造器,带参或泛型需显式指定类型并分步处理。

反射创建对象本身不难,难在绕不开的类型安全、构造器匹配和参数绑定问题——多数报错都卡在这三步上。
用 Activator.CreateInstance 创建无参对象最稳妥
这是最常用也最不容易出错的方式,适用于有 public 无参构造函数的类型。
- 直接传入
Type对象即可:Activator.CreateInstance(typeof(MyClass)) - 如果类型是泛型,必须用已构造类型(如
typeof(List<string>)</string>),不能用开放泛型(如typeof(List)) - 注意:若类只有 private 或带参构造器,会抛出
MissingMethodException
带参构造器必须显式指定参数类型和值
反射不会自动推导重载构造器,Activator.CreateInstance 的参数顺序和类型必须严格匹配目标构造器签名。
- 错误写法:
Activator.CreateInstance(typeof(DateTime), 2024, 1, 1)—— 这里传的是int,但DateTime(int, int, int)实际要求的是int, int, int,看似对实则可能因重载歧义失败 - 推荐写法:先用
type.GetConstructor(new[] { typeof(int), typeof(int), typeof(int) })显式获取构造器,再调用ctor.Invoke(new object[] { 2024, 1, 1 }) - 参数为
null时,需用typeof(string)等明确类型占位,不能只传null
泛型类型创建要分两步:先构造,再实例化
像 List<t></t> 这类开放泛型不能直接 new,必须先用 MakeGenericType 补全类型参数。
- 正确流程:
var genericType = typeof(List).MakeGenericType(typeof(string)); var list = Activator.CreateInstance(genericType); - 如果泛型参数本身也是泛型(如
Dictionary<string list>></string>),嵌套调用MakeGenericType即可,但要注意层级和顺序 -
Activator.CreateInstance对泛型类型的性能开销比普通类型略高,高频场景建议缓存构造器或用表达式树预编译
替代方案:用 FormatterServices.GetUninitializedObject 绕过构造器(慎用)
它直接分配内存并返回对象引用,不调用任何构造器,适用于反序列化等特殊场景。
- 适用条件:类型必须是引用类型,且不能有
[SecurityCritical]或unsafe构造逻辑 - 风险:字段全是默认值(
0/null),readonly字段也无法初始化,后续手动赋值容易遗漏 - 常见误用:拿它代替
CreateInstance图省事,结果对象处于半初始化状态,运行时突然崩在某个未检查的null上
真正麻烦的不是怎么调用反射 API,而是你永远不知道目标类型到底有几个构造器、参数是不是可空、有没有 [Obsolete] 或 [SecuritySafeCritical] 修饰——这些细节往往只在运行时报错才暴露出来。


















