C#/.Net的多播委托到底是啥?彻底剖析下-焦点观察
委托在.Net里面被托管代码封装了之后,看起来似乎有些复杂。但是实际上委托即是函数指针,而多播委托,即是函数指针链。本篇来只涉及底层的逻辑,慎入。
(资料图片仅供参考)
概括1.示例代码
public delegate void ABC(); //委托写在类的外面public class Test{ public ABC AAA; public void A() { } public void B() { }}static void Main(string[] args){ Test test = new Test(); test.AAA += new ABC(test.A); test.AAA += new ABC(test.B); test.AAA(); //test.AAA.Invoke();}
以上的test.AAA+=的等号后面每放一个函数,就相当于多了一个函数指针。号称:多播委托。
2.多播原理伪代码以上委托可以简化成以下伪代码,其它所有多播委托均可依次类推。
int i;// i表示多播委托的次数if(i==1) //也就是只test.AAA += new ABC(test.A);然后调用test.AAA(){ test.A() //只有一个多播,直接调用这一个函数}else // 如果大于一个多播委托,如示例两个多播{ IntPtr FunPtr=test.A()+test.B(); //函数A和函数B形成了一个新的托管地址 FunPtr();//在新形成的托管地址里面分别调用函数A和函数B}
3.内存模型对象(object)的内存,大致是:
为了简洁,实质非常庞大header+MethodTable+field
委托根据对象来,以示例代码的test对象为例,test对象有一个filed也即是委托类型的变量AAA。AAA则是new ABC得来的。new ABC所实例化对象的filed是分别为函数A,B。那么他们的内存模型如下所示:
test==header+Mehtodtalbe + AAA(test.AAA(1) or test.AAA(2)+test.AAA(1))test.AAA(1)==new ABC(test.A):header+Methodtable+函数A(precode)test.AAA(2)==new ABC(test.B):header+Methodtable+函数B(precode)
特例:当只有一个多播委托(多播伪代码里的i==1),类似于以下这种情况:
如果:static void Main(string[] args){ Test test = new Test(); test.AAA += new ABC(test.A);//只有一个多播 test.AAA(); //test.AAA.Invoke();}那么:test==header+Mehtodtalbe + AAA(test.AAA(1))test.AAA(1)==new ABC(test.A)(header+Methodtable+函数A(precode,offset:0x18))内存:0x000001DB38D552C0 00007ffa3b3654d8 000001db38d55858这里的0x000001DB38D552C0即test的MethodTable地址。000001db38d55858即new ABC(test.A)的MethodTable地址
委托里面只有一个方法test.A(多播伪代码里的i==1),这种情况的话,JIT会直接寻找test.AAA(1)的MethodTable,加上偏移位0x18,也即是函数test.A的函数地址。然后运行。
注意了,因为对象test只有一个filed:AAA。超过一个以上的多播(多播伪代码里的i!=1,也即else逻辑),它的field是一直变化的,比如new ABC(test.A)的时候,它的filed是test.AAA(1)。而new ABC(test.B)的时候,它的field则是test.AAA(2)+test.AAA(1)组合成的托管函数,覆盖掉前面的。如果有test.AAA(3),那么后面继续组合,继续覆盖test对象的field。
当它组合之后,形成一个新的地址,CLR会在这个地址的基础上加上偏移量0x18(同上特例)进行托管函数代码调用。JIT Compile之后,在里面分别调用函数test.A,test.B,完成委托的多播。参照如下代码:
test.AAA(); //test.AAA.Invoke();00007FFA3AFF7A27 mov rcx,qword ptr [rbp+28h]00007FFA3AFF7A2B mov rcx,qword ptr [rcx+8]00007FFA3AFF7A2F mov rax,qword ptr [rbp+28h]00007FFA3AFF7A33 call qword ptr [rax+18h]00007FFA3AFF7A36 nop
4.托管和非托管依次调用顺序,以下函数按照顺序在多播委托中调用:托管:
System.MulticastDelegate:CtorClosed //把对象test对象的field设置为abcSystem.Delegate:Combine //组合成新的委托,也即函数指针链,如果只有一个多播,则即那一个函数指针System.Runtime.CompilerServices.CastHelpers.ChkCastClass //进行类型转换
非托管:
JIT_WriteBarrier //设置card_table,防止GC标记的时候漏掉
5.原理图多播委托原理如下图所示:单个委托实际上就是调用函数指针,而多个委托,则是通过多播委托组合单个委托形成一个新的托管函数,在这个托管函数里面进行单个函数一一调用。
结尾作者:江湖评谈关注公众号:jianghupt。后台回复:dotnet7。获取一套.Net7 CLR源码教程。
关键词:
相关阅读
-
C#/.Net的多播委托到底是啥?彻底剖析下...
前言委托在 Net里面被托管代码封装了之后,看起来似乎有些复杂。但是 -
2023年养老金上调方案最新消息公布!安...
上个月底养老金调整方案公布,2023年企业事业单位退休人员养老金上调3 -
【世界新视野】各部门积极保障端午假期...
新华社北京6月21日电(记者樊曦、周圆)端午假期即将开启,各地出行客 -
趁他病要他命:扎克伯格“捅刀”推特,...
在马斯克去年宣布收购推特几周后,Meta就开始开发预计将被称为Threads -
下周最具爆发力三大黑马股推荐(6月26日)
推荐黑马股1:大通退(000038):退市整理的证券推荐理由沪深交易所2023 -
广西部署做好端午假期消费促进和市场保...
为保障端午假期期间消费市场供应平稳有序,持续释放节日消费潜力,自治 -
热头条丨团代表故事丨95后赵梦:青年要...
中国青年网北京6月20日电(记者马志强王增强邵志凯)95后团代表赵梦是 -
Keep通过港交所聆讯:2023年一季度营收4...
6月21日,运动科技平台Keep在港交所披露通过聆讯后的招股书,即将在香 -
南社区党建引领夏季灭“四害”
点击蓝字点注我们为进一步降低蚊虫密度,提升小区整体环境,控制和减少 -
环球视点!soncap认证怎么查(soncap认证)
您好,现在蔡蔡来为大家解答以上的问题。soncap认证怎么查,soncap认证 -
热点聚焦:哈德胜任命邱华景为公司财务...
挖贝网6月21日,哈德胜(873950)发公告称,根据《公司法》及《公司章 -
全球热头条丨前海香港商会工程建设专委...
深圳新闻网2023年6月22日讯(深圳特区报记者张智伟通讯员危茜)6月21日 -
当前讯息:渤海化学(600800.SH):截止目...
格隆汇6月21日丨渤海化学(600800 SH)在2023年6月21日业绩说明会上表示 -
全球报道:平方符号怎么打出来_平方符号
1、电线1平方符号是1mm2。以上就是【平方符号怎么打出来,平方符号】相 -
中国竞彩网欧青赛情报:德国曾在预选赛...
周四003欧青赛德国U21VS以色列U21卫冕冠军德国U21在本次欧青赛预选赛中 -
多图!1.8万平方米的黄浦滨江“大衣料”...
初夏夜,江风徐来。挑一本好书,嘬一口咖啡特调,在日落月升之际,90后 -
当前动态:行走黄河看三晋 | 吉县太度...
太度村口。山西吉县黄河壶口瀑布东边,人祖山脚下,有一个千年古村... -
世界球精选!蔚来受邀出席中德企业家圆...
当地时间6月20日,蔚来、国家电网、工商银行、商汤科技等15家中德企 -
环球快播:前郭法院开展防范非法集资和...
6月20日,前郭县人民法院组织干警前往前郭县体育场,开展了以“高利是 -
宋广元窑黄釉褐彩瓷盏|环球快播
1、宋广元窑黄釉褐彩瓷盏是重庆中国三峡博物馆收藏的瓷器。文章到此就