dotnet 委托的实现解析

最近被问到什么是.Net中的委托。问题虽然简单却无从回答。只能说委托是托管世界的函数指针,这么说没啥大毛病,但也都是毛病(当时自己也知道这么说不太对,不过自己不太爱用这个也没准备确实没有更好的答案)。

执行效率

正巧前段时间看Core CLR的文档看到不同方式调用函数效率的比较正巧有这个,摘录如下。这段内容在 clr官方文档
的 为什么反射很慢 ?里。

Reading a Property (‘Get’) Method Mean StdErr Scaled Bytes Allocated/Op
GetViaProperty   0.2159 ns   0.0047 ns   1.00   0.00  
GetViaDelegate   1.8903 ns   0.0082 ns   8.82   0.00  
GetViaILEmit   2.9236 ns   0.0067 ns   13.64   0.00  
GetViaCompiledExpressionTrees   12.3623 ns   0.0200 ns   57.65   0.00  
GetViaFastMember   35.9199 ns   0.0528 ns   167.52   0.00  
GetViaReflectionWithCaching   125.3878 ns   0.2017 ns   584.78   0.00  
GetViaReflection   197.9258 ns   0.2704 ns   923.08   0.01  
GetViaDelegateDynamicInvoke   842.9131 ns   1.2649 ns   3,931.17   419.04  
Writing a Property (‘Set’) Method Mean StdErr Scaled Bytes Allocated/Op
SetViaProperty   1.4043 ns   0.0200 ns   6.55   0.00  
SetViaDelegate   2.8215 ns   0.0078 ns   13.16   0.00  
SetViaILEmit   2.8226 ns   0.0061 ns   13.16   0.00  
SetViaCompiledExpressionTrees   10.7329 ns   0.0221 ns   50.06   0.00  
SetViaFastMember   36.6210 ns   0.0393 ns   170.79   0.00  
SetViaReflectionWithCaching   214.4321 ns   0.3122 ns   1,000.07   98.49  
SetViaReflection   287.1039 ns   0.3288 ns   1,338.99   115.63  
SetViaDelegateDynamicInvoke   922.4618 ns   2.9192 ns   4,302.17   390.99  

上表分别列出了读取和设置属性通过不同方式的耗时等结果,我们可以看到直接通过属性读取和通过委托读取速度的平均值相差了接近10倍。这么看委托显然就不是函数指针了(函数指针的性能损失很小),那么下面就具体看下究竟是啥。

解析

先上实例代码如下:

internal class HelloWorld { public static void HelloWorld1() { Console.WriteLine("hello world1"); } public delegate void SayHi(); public void Main() { SayHi? helloWorld = new SayHi(HelloWorld1); helloWorld.Invoke(); } }

很简单的代码,编译后用ILSpy打开。

元数据与IL

首先看下元数据表,毫不例外的在02 TypeDef表里找到了委托对象类型定义,毕竟一切皆对象,这个应该和事件是一个处理方法。

Name BaseType FieldList MethodList
SayHi   0x100000E   0x4000000   0x600006  

剩下的表暂时先不看了(主要时间太长不记得类型方法在表里是咋对应起来的了)

下面先把类型SayHi的定义相关的IL代码贴出来

.class nested public auto ansi sealed SayHi     extends [System.Runtime]System.MulticastDelegate {     // Methods     .method public hidebysig specialname rtspecialname          instance void .ctor (             object 'object',             native int 'method'         ) runtime managed      {     } // end of method SayHi::.ctor     .method public hidebysig newslot virtual          instance void Invoke () runtime managed      {     } // end of method SayHi::Invoke     .method public hidebysig newslot virtual          instance class [System.Runtime]System.IAsyncResult BeginInvoke (             class [System.Runtime]System.AsyncCallback callback,             object 'object'         ) runtime managed      {     } // end of method SayHi::BeginInvoke     .method public hidebysig newslot virtual          instance void EndInvoke (             class [System.Runtime]System.IAsyncResult result         ) runtime managed      {     } // end of method SayHi::EndInvoke } // end of class SayHi

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgjszz.html