优化委托的 DynamicInvoke
Intro
委托方法里有一个 DynamicInvoke
的方法,可以在不清楚委托实际类型的情况下执行委托方法,但是用 DynamicInvoke
去执行的话会比直接用 Invoke
的方法会慢上很多,差了两个数量级,所以在知道委托类型的情况下尽可能使用 Invoke
执行,但有时候我们并不知道委托的实际类型,比如在很多类库项目中可能并不是强类型的委托
优化方法
优化方法,直接执行委托的对应的方法, DynamicInvoke
实际也是调用的对应的方法,我们如果执行调用对应的方法就可以优化
delegate func = (Func<string, string>)str=> "12345";
string paramString = "321";
// Invoke
((Func<string, string>)func).Invoke(paramString);
// DynamicInvoke
func.DynamicInvoke(new object[]{ paramString });
// Method Invoke
func.Method.Invoke(func.Target, new object[]{ paramString });
性能测试
下面做一个性能测试,测试代码如下:
public class DelegateInvokeTest
{private readonly Delegate _func, _func1;private readonly string parameter;private readonly int paramInt;public DelegateInvokeTest(){parameter = "Test";paramInt = 1;_func = (Func<string, string>)(str => str);_func1 = (Func<int, int>)(val => 0);}[Benchmark(Baseline = true)]public object Invoke(){return ((Func<string, string>)_func).Invoke(parameter);}[Benchmark]public object InvokeBoxing(){return ((Func<int, int>)_func1).Invoke(paramInt);}[Benchmark]public object DynamicInvoke(){return _func.DynamicInvoke(parameter);}[Benchmark]public object DynamicInvokeBoxing(){return _func1.DynamicInvoke(paramInt);}[Benchmark]public object MethodInfoInvoke(){return _func.Method?.Invoke(_func.Target, new object[] { parameter });}[Benchmark]public object MethodInfoInvokeBoxing(){return _func1.Method?.Invoke(_func1.Target, new object[] { paramInt });}[Benchmark]public object ReflectInvoke(){var funcType = typeof(Func<,>).MakeGenericType(typeof(string), typeof(string));var method = funcType.GetProperty("Method")?.GetValueGetter()?.Invoke(_func) as MethodInfo;var target = funcType.GetProperty("Target")?.GetValueGetter()?.Invoke(_func);return method?.Invoke(target, new object[] { parameter });}[Benchmark]public object ReflectInvokeBoxing(){var funcType = typeof(Func<,>).MakeGenericType(typeof(string), typeof(int));var method = funcType.GetProperty("Method")?.GetValueGetter()?.Invoke(_func1) as MethodInfo;var target = funcType.GetProperty("Target")?.GetValueGetter()?.Invoke(_func1);return method?.Invoke(target, new object[] { paramInt });}
}
测试结果如下:
由上面的结果,我们可以看出来,直接调用方法的性能虽然还是比 Invoke
慢上好多,但是相比 DynamicInvoke
已经优化 70% 左右,对于有装箱操作的性能会稍差一些,比 DynamicInvoke
优化可达 44% 左右。
Reference
https://github.com/WeihanLi/PerformanceTest/blob/master/PerformanceTest/ReflectionTests/DelegateInvokeTest.cs
https://github.com/WeihanLi/PerformanceTest/blob/master/PerformanceTest/BenchmarkDotNet.Artifacts/results/PerformanceTest.ReflectionTests.DelegateInvokeTest-report-github.md