MethodInfo.Invoke 调用实例方法必须传入目标对象
直接对实例方法调用
MethodInfo.Invoke(null, args)会抛出
TargetException: Object reference not set to an instance of an object。这是因为实例方法隐含一个
this参数,反射必须知道调用在哪个对象上。
正确做法是先获取实例(比如 new 出来或从容器中取),再把该实例作为第一个参数传给
Invoke:
var obj = new Calculator();
var method = typeof(Calculator).GetMethod("Add");
var result = method.Invoke(obj, new object[] { 5, 3 }); // 返回 8
静态方法才允许传 null作第一个参数 若目标对象为
null且方法非静态,异常发生在运行时,编译不报错 泛型方法需先用
MakeGenericMethod构造封闭类型,再调用
Invoke
参数类型不匹配会导致 TargetParameterCountException 或 ArgumentException
Invoke不自动做类型转换,哪怕数值上兼容(如传
int给
long参数)也会失败。错误信息通常是
System.ArgumentException: Object of type 'System.Int32' cannot be converted to type 'System.Int64'。
解决方式是显式转换参数数组:
var args = new object[] { (long)5, (long)3 };
method.Invoke(obj, args);
使用 Convert.ChangeType(value, paramType)可适配更多类型组合 注意值类型装箱后仍是原类型,不会“升级”成父类型 如果参数含
ref或
out,对应位置必须传
object引用(如
new object[] { refVar }),且调用后需手动解包
性能差、异常多,别在热路径里反复用 MethodInfo.Invoke
每次
Invoke都要校验访问权限、参数个数、类型兼容性、执行上下文等,开销远高于直接调用。实测比直接调用慢 50–100 倍以上。
高频场景建议缓存委托:
var del = (Func<int, int, int>)Delegate.CreateDelegate(
typeof(Func<int, int, int>), obj, method);
var result = del(5, 3); // 快,且类型安全
Delegate.CreateDelegate仅支持公开实例/静态方法;私有方法需用
BindingFlags.NonPublic并确保有权限 .NET 5+ 推荐用
DynamicMethod或表达式树生成委托,更灵活 若只是偶尔调用(如插件加载、配置驱动逻辑),
Invoke完全够用,不必过度优化
调用泛型方法前必须先构造具体类型
直接对开放泛型方法(如
List<t>.Add(T)</t>)调用
Invoke会失败,因为 CLR 不允许执行未闭合的泛型签名。
必须用
MakeGenericMethod显式指定类型参数:
var list = new List<string>();
var method = typeof(List<string>).GetMethod("Add");
// 注意:这里 method 已是 closed 类型,可直接 Invoke
method.Invoke(list, new object[] { "hello" });
// 若只有开放泛型类型(如 typeof(List<>)),则:
var openMethod = typeof(List<>).GetMethod("Add");
var closedMethod = openMethod.MakeGenericMethod(typeof(string));
closedMethod.Invoke(list, new object[] { "world" });
MakeGenericMethod返回新
MethodInfo,原对象不变 泛型约束(如
where T : class)会在
MakeGenericMethod时检查,不满足则抛
ArgumentException泛型类型参数不能是
var或运行时才知的
Type变量——必须在调用前确定 实际用起来最常卡在参数类型和对象实例这两处,尤其是从 JSON 或配置读参数后直接塞进
Invoke,很容易因隐式类型丢失崩掉。
