MethodInfo.Invoke 是高并发下的主要性能瓶颈,因其触发完整反射解析流程、引发高频堆分配与 GC 压力;推荐用 Delegate.CreateDelegate 或 Expression.Compile 缓存强类型委托以提升 10–30 倍性能。
MethodInfo.Invoke 是高并发下的主要性能瓶颈
在 Web API 或高频服务中,直接用 MethodInfo.Invoke 调用方法,会触发完整的反射解析流程:类型检查、参数绑定、访问权限校验、装箱/拆箱(值类型)、异常包装。单次调用开销约是直接调用的 50–100 倍;并发量上来后,GC 压力和 CPU 竞争会急剧放大。
Invoke 都新建 object[] 参数数组,引发堆分配ref/out 参数时,绑定逻辑更重,容易抛 TargetParameterCountException
Delegate.CreateDelegate 替代 Invoke 可提速 10–30 倍将反射获取的 MethodInfo 编译为强类型委托,后续调用就等同于原生方法调用。关键在于:委托只创建一次,复用在所有请求中。
var method = typeof(MyService).GetMethod("Process");
// 推荐:指定委托类型,避免 object[] 拆包
var func = (Func)Delegate.CreateDelegate(
typeof(Func),
null,
method);
// 后续直接调用,无反射开销
var result = func(instance, 42);
method 是静态或实例方法,并与委托签名严格匹配(含 this 参数位置)List.Add ),需先用 MakeGenericMethod 闭合Lazy 或 ConcurrentDictionary 存储Expression.Lambda 编译动态委托适合复杂绑定场景当参数需运行时映射(如从 IDictionary 构建调用参数)、或涉及属性访问/转换时,Expression 比 CreateDelegate 更灵活,且编译后性能几乎无损。
var instanceParam = Expression.Parameter(typeof(object), "instance"); var argParam = Expression.Parameter(typeof(object), "arg"); var convertedArg = Expression.Convert(argParam, typeof(int)); var call = Expression.Call( Expression.Convert(instanceParam, typeof(MyService)), typeof(MyService).GetMethod("Process"), convertedArg ); var lambda = Expression.Lambda
>(call, instanceParam, argParam); var compiled = lambda.Compile(); // 一次性编译 // 复用 compiled var result = compiled(serviceObj, 42);
InvalidOperationException,应在初始化阶段验证Compile(),它不可缓存且触发 JIT很多框架(如早期 ASP.NET Core Model Binding)会在每次请求中重新获取 PropertyInfo、调用 GetValue,这比方法调用更糟——属性访问还涉及索引器、get_ 方法查找、BindingFlags 过滤等额外步骤。
PropertyInfo 和对应 getter/setter 委托缓存在静态字典里,键可为 (Type, PropertyName)
System.Reflection.Metadata + MetadataReader 在启动时预扫描类型,生成轻量元数据缓存,绕过运行时反射 API反射不是不能用,而是不能“裸用”。高并发下,任何未缓存、未编译、未静态化的反射操作,都会成为吞吐量的隐形天花板。