C# 反射调用方法方法 C#如何使用MethodInfo.Invoke动态调用方法

发布时间 - 2026-02-01 00:00:00    点击率:
MethodInfo.Invoke调用实例方法必须传入目标对象,传null会抛TargetException;静态方法才允许传null。泛型方法需先用MakeGenericMethod构造封闭类型,参数类型不匹配需显式转换,性能差建议缓存委托。

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 不自动做类型转换,哪怕数值上兼容(如传 intlong 参数)也会失败。错误信息通常是 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) 可适配更多类型组合
  • 注意值类型装箱后仍是原类型,不会“升级”成父类型
  • 如果参数含 refout,对应位置必须传 object 引用(如 new object[] { refVar }),且调用后需手动解包

性能差、异常多,别在热路径里反复用 MethodInfo.Invoke

每次 Invoke 都要校验访问权限、参数个数、类型兼容性、执行上下文等,开销远高于直接调用。实测比直接调用慢 50–100 倍以上。

高频场景建议缓存委托:

var del = (Func)Delegate.CreateDelegate(
    typeof(Func), obj, method);
var result = del(5, 3); // 快,且类型安全
  • Delegate.CreateDelegate 仅支持公开实例/静态方法;私有方法需用 BindingFlags.NonPublic 并确保有权限
  • .NET 5+ 推荐用 DynamicMethod 或表达式树生成委托,更灵活
  • 若只是偶尔调用(如插件加载、配置驱动逻辑),Invoke 完全够用,不必过度优化

调用泛型方法前必须先构造具体类型

直接对开放泛型方法(如 List.Add(T))调用 Invoke 会失败,因为 CLR 不允许执行未闭合的泛型签名。

必须用 MakeGenericMethod 显式指定类型参数:

var list = new List();
var method = typeof(List).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,很容易因隐式类型丢失崩掉。


# js  # json  # c#  # .net  # gate  # gate.  # Object  # NULL  # 父类  # int  # class  # 值类型  # 参数数组  # Delegate  # 委托  # 泛型  # var  # 类型转换  # 对象  # this  # 第一个  # 先用  # 不匹配  # 直接调用  # 也会  # 都要  # 会在  # 是从  # 很容易  # 仍是 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 深圳网站制作的公司有哪些,dido官方网站?  Laravel集合Collection怎么用_Laravel集合常用函数详解  如何基于云服务器快速搭建网站及云盘系统?  如何利用DOS批处理实现定时关机操作详解  Python结构化数据采集_字段抽取解析【教程】  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  网页设计与网站制作内容,怎样注册网站?  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  如何在建站之星网店版论坛获取技术支持?  JavaScript实现Fly Bird小游戏  香港网站服务器数量如何影响SEO优化效果?  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  浅析上传头像示例及其注意事项  昵图网官网入口 昵图网素材平台官方入口  如何在阿里云ECS服务器部署织梦CMS网站?  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  百度浏览器如何管理插件 百度浏览器插件管理方法  如何在腾讯云免费申请建站?  Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】  Android滚轮选择时间控件使用详解  C++用Dijkstra(迪杰斯特拉)算法求最短路径  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法  nginx修改上传文件大小限制的方法  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  米侠浏览器网页图片不显示怎么办 米侠图片加载修复  如何生成腾讯云建站专用兑换码?  如何在七牛云存储上搭建网站并设置自定义域名?  如何快速重置建站主机并恢复默认配置?  Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧  网站制作软件有哪些,制图软件有哪些?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  详解jQuery中基本的动画方法  Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】  如何在IIS中新建站点并配置端口与IP地址?  Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】  Laravel Fortify是什么,和Jetstream有什么关系  如何实现javascript表单验证_正则表达式有哪些实用技巧  JS中对数组元素进行增删改移的方法总结  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  如何用免费手机建站系统零基础打造专业网站?  电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?  中国移动官方网站首页入口 中国移动官网网页登录  图册素材网站设计制作软件,图册的导出方式有几种?  网站制作价目表怎么做,珍爱网婚介费用多少?  Laravel如何使用模型观察者?(Observer代码示例)  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】