不检查方法存在时,使用Reflection或动态方法的最佳实践是什么?
嘿,这个问题问到点子上了——当你100%笃定目标方法肯定存在,完全不需要做存在性检查时,反射和动态方法的最佳实践核心就是「榨干性能+保持代码清爽」,下面我分模块给你唠唠:
缓存反射对象,别重复“找钥匙”
别每次调用都去执行GetType().GetMethod(...),这步查找操作的开销比你想象的大。把MethodInfo实例提前缓存到静态字段或者全局字典里,后续直接复用就行:// 提前初始化并缓存MethodInfo private static readonly MethodInfo _targetMethod = typeof(MyClass).GetMethod( "MyMethod", BindingFlags.Public | BindingFlags.Instance ); // 后续调用直接用缓存的实例 _targetMethod.Invoke(myInstance, new object[] { param1, param2 });优先转成强类型委托,性能逼近普通方法
Invoke是晚绑定,性能不如直接调用方法。把MethodInfo转换成对应的强类型委托(比如Action<T>、Func<TResult>),调用起来和普通方法几乎没区别,性能提升非常明显:// 假设目标方法是 public void MyMethod(string arg) private static readonly Action<MyClass, string> _myMethodDelegate = (Action<MyClass, string>)Delegate.CreateDelegate( typeof(Action<MyClass, string>), _targetMethod ); // 调用时直接像普通方法一样用 _myMethodDelegate(myInstance, "hello world");跳过不必要的访问检查(如果需要)
如果要调用非公开方法,获取MethodInfo时加上BindingFlags.DoNotCheckVisibility,或者在创建委托时直接跳过可见性校验,避免额外的权限检查开销。减少装箱拆箱,复用参数数组
用Invoke时,参数会被包装成object[],容易产生GC压力。如果必须用Invoke,尽量复用同一个参数数组,别每次都新建。
动态方法适合需要极致性能,或者要生成自定义逻辑的场景,核心原则还是缓存+强类型:
缓存生成的委托,别重复生成IL
动态方法的IL生成过程开销极大,生成后一定要把它转换成委托缓存起来,后续直接调用委托就行,别每次都重新生成。生成强类型IL,避免装箱拆箱
尽量生成对应方法签名的强类型委托(比如Action<MyClass, int>),别用object类型的参数/返回值,减少不必要的装箱拆箱操作,性能能再上一个台阶。跳过可见性检查,直接访问非公开成员
创建DynamicMethod时,用带skipVisibility参数的重载,把这个参数设为true,就能直接访问目标类型的非公开方法,不需要额外的权限操作。复用IL生成逻辑,减少重复代码
如果有多个类似的动态方法需求,把IL生成的逻辑封装成工具类,根据不同的方法签名复用模板,别每次都写一遍重复的IL指令。
别滥用“不检查”的前提
一定要确保你真的100%确定方法存在——比如是你自己维护的代码库,或者通过编译时代码生成、特性标记等手段做了验证。否则一旦方法被改名、删除,运行时直接抛MissingMethodException,排查起来头大。性能测试先行
反射缓存委托和动态方法的性能差异在不同场景下不一样:小量调用时差距不大,高频调用时动态方法可能更优。最好根据你的实际场景做个简单的性能基准测试,再选合适的方案。平衡性能和可读性
别为了极致性能写出一堆没人能看懂的IL代码,如果反射缓存委托已经能满足性能需求,优先用反射,代码更易维护。
内容的提问来源于stack exchange,提问作者Victor Fedorenko

