技术开发 频道

.NET面面观——探索.Net中的委托

  实际上你还可以再编写一个与MyDelegate相同签名的委托,然后也指向一个静态方法,使用相同的方法查看该委托的_methodPtr的值,你会发现这个新委托与MyDelegate的_methodPtr的值是一致的。

  刚才不是说这个时候_methodPtr指向的是一个Stub么,既然如此那我们反汇编一下代码:

  !u 007809C4

  Unmanaged code

  007809C4 8BC1 mov eax,ecx

  007809C6 8BCA mov ecx,edx

  007809C8 83C010 add eax,10h

  007809CB FF20 jmp dword ptr [eax]

  ........

  .Net里JIT的方法的调用约定是Fast Call,对于Fast Call来说,方法的前两个参数会放在ECX和EDX两个寄存器中。那么mov eax,ecx实际上就是将_target传递给eax,再看看

  704bb188 4000102 10 System.IntPtr 1 instance 0025C018 _methodPtrAux

  _methodPtrAux的偏移是10,这里的add eax,10h就是将eax指向_methodPtrAux,然后jmp dword ptr[eax]就是跳转到_methodPtrAux所指向的地址了,就是委托指向的那个静态方法。

  通过委托调用方法

  如何通过委托调用方法呢:

  public void CallByDelegate()  
{  
    MyDelegate myDelegate
= new MyDelegate(this.Test);  
    
    myDelegate(
5);  
}

  再来看看其对应的IL代码:

.method public hidebysig instance void  CallByDelegate() cil managed  
{  
  
// Code size       21 (0x15)  
   .maxstack  3  
   .locals init ([
0] class Yuyijq.DotNet.Chapter2.MyDelegate myDelegate)  
   IL_0000:  ldarg.
0  
   IL_0001:  ldftn instance
void Yuyijq.DotNet.Chapter2.TestDelegate::Test(int32)  
   IL_0007:  newobj instance
void Yuyijq.DotNet.Chapter2.MyDelegate::.ctor(object, native int)  
   IL_000c:  stloc.
0  
   IL_000d:  ldloc.
0  
   IL_000e:  ldc.i4.
5  
   IL_000f:  callvirt   instance
void Yuyijq.DotNet.Chapter2.MyDelegate::Invoke(int32)  
   IL_0014:  ret  
14: }

  前面的代码我们已经熟悉,最关键的就是

  callvirt instance void Yuyijq.DotNet.Chapter2.MyDelegate::Invoke(int32)

  我们发现,通过委托调用方法,实际上就是调用委托的Invoke方法。

  多播的委托

  好了,既然已经解释了面向对象和类型安全,那么说委托是多播的咋解释?

  你可能已经发现,MyDelegate继承自MulticastDelegate,看这个名字貌似有点意思了。来看看下面这两行代码:

MyDelegate myDelegate = new MyDelegate(this.Test);  
myDelegate
+= new MyDelegate(this.Test1);

  通过IL我们可以发现,这里的+=最后就是调用System.Delegate的Combine方法。而Combine的真正实现时在MulticastDelegate的CombineImpl方法中。在MulticastDelegate中有一个_invocationList字段,从CombineImpl中可以看出这个字段是一个object[]类型的,而委托链就放在这个数组里。

  后记

  文章是想到哪儿写到哪儿,写的比较乱,也比较匆忙。非常抱歉。对于中间那段奇妙的事情,我原来真的不知道,我一直以为当委托指向一个静态方法时,_target指向null就完事儿了,没想到还有这么一番景象。看来很多东西还是不能想当然,亲身尝试一下才知道真实的情况。

查看原文

0
相关文章