将方法反射调用转为Func<Task>传入基准测试方法的正确方式
解决方法
你只需要将Invoke返回的object强转为Task类型即可直接await,因为你要调用的异步方法返回值必然是Task或Task<T>类型,两者都可安全转换为Task基类。
基础实现代码
AsyncBenchmarker.BenchmarkAsync(async () => { // 反射获取目标方法 var method = benchmark.GetType().GetMethod("SomeOtherMethod"); if (method == null) { throw new InvalidOperationException("未找到指定的基准测试方法"); } // 强转为Task后await var executeTask = (Task)method.Invoke(benchmark, null)!; await executeTask; }, attribute.Repetitions, false).Wait();
优化写法(推荐)
注意不要把GetMethod逻辑放到lambda内部,否则反射查找方法的耗时会被计入基准测试结果,导致统计数据不准确。可以提前在外部缓存MethodInfo:
// 提前缓存反射得到的方法元数据,不计入测试耗时 var targetMethod = benchmark.GetType().GetMethod("SomeOtherMethod"); if (targetMethod == null) { throw new InvalidOperationException("找不到指定的测试方法"); } // 执行基准测试 AsyncBenchmarker.BenchmarkAsync(async () => { var task = (Task)targetMethod.Invoke(benchmark, null)!; await task; }, attribute.Repetitions, false).Wait();
注意事项
- 如果目标方法是同步方法(返回值为void),需要额外包装为异步任务:
await Task.Run(() => targetMethod.Invoke(benchmark, null)); - 如果目标方法需要传入参数,替换
Invoke的第二个参数null为对应的参数数组即可 - 若目标方法返回
Task<T>,强转为Task不会影响执行逻辑,也不会丢失返回值的执行过程
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

