C#的delegate原理

??先來看一段代碼:

class AClass
{
    public delegate int MyDelegate(string str);
    public MyDelegate myDelegate;
}

class Program
{
    static void Main(string[] args)
    {
        int LocalFunction(string a)
        {
            return 789;
        }

        AClass aClass = new AClass();
        aClass.myDelegate += t => { return 123; };
        aClass.myDelegate -= t => { return 456; };
        aClass.myDelegate -= LocalFunction;
        aClass.myDelegate += LocalFunction;

        aClass.myDelegate = new AClass.MyDelegate(LocalFunction);
        aClass.myDelegate?.Invoke("");
    }
}

??編譯生成exe可執(zhí)行文件胳蛮,并反編譯IL得到代碼如下:


反編譯IL得到的結果(圖一)

??接著再看AClass是什么樣子的:


AClass(圖二)

??根據(jù)圖上可知,委托MyDelegate最終會被生成為一個類呜达,并且繼承于MulticastDelegate乙漓,MulticastDelegate繼承Delegate吨铸,而myDelegate則是它的實例债蜜。當我們對委托+= 操作時候钙勃,其實是調(diào)用了Delegate.Combine()函數(shù)蛛碌,如上圖的匿名函數(shù),會被傳進Combine中辖源,并返回一個新的Delegate對象給myDelegate蔚携。-=操作會調(diào)用Remove函數(shù)。不知道你注意到?jīng)]有克饶,當我們寫一個匿名函數(shù)傳遞給委托時候酝蜒,會被生成一個函數(shù),例如圖一的b__0_1和b__0_2矾湃,也就是說每次綁定的匿名函數(shù)都會被生成一個帶名字的函數(shù)亡脑,哪怕你寫的匿名函數(shù)一模一樣,編譯后都不是同一個東西邀跃。但如果不是匿名函數(shù)远豺,像LocalFunction,委托的+=和-=都是對同一個函數(shù)操作坞嘀。

??我們不妨再看看源碼Delegate.Combine()怎么玩轉的:

public static Delegate Combine(Delegate a, Delegate b)
{
    if (a == null)
    {
        return b;
    }
    return a.CombineImpl(b);
}

protected virtual Delegate CombineImpl(Delegate d)
{
    throw new MulticastNotSupportedException(Environment.GetResourceString("Multicast_Combine"));
}

??CombineImpl是虛函數(shù)躯护,會調(diào)用帶子類MulticastDelegate.CombineImpl(),代碼太多丽涩,只貼一部分:

protected sealed override Delegate CombineImpl(Delegate follow)
{
    if (follow == null)
    {
        return this;
    }
    if (!Delegate.InternalEqualTypes(this, follow))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));
    }
    MulticastDelegate multicastDelegate = (MulticastDelegate)follow;
    int num = 1;
    object[] array = multicastDelegate._invocationList as object[];
    if (array != null)
    {
        num = (int)multicastDelegate._invocationCount;
    }
    object[] array2 = this._invocationList as object[];
    int num2;
    object[] array3;
    if (array2 == null)
    {
        num2 = 1 + num;
        array3 = new object[num2];
        array3[0] = this;
        if (array == null)
        {
            array3[1] = multicastDelegate;
        }
        else
        {
            for (int i = 0; i < num; i++)
            {
                array3[1 + i] = array[i];
            }
        }
        return this.NewMulticastDelegate(array3, num2);
    }

看到這里大概都能猜到了棺滞,每個委托類無非就是包含了一個數(shù)組,數(shù)組記錄了多個Delegate矢渊,當我們編寫+=继准,把回調(diào)函數(shù)的包裝類MulticastDelegate的數(shù)據(jù)合并到另一個MulticastDelegate中,一旦執(zhí)行invoke矮男,便調(diào)用所有的回調(diào)函數(shù)移必。

Author : SunnyDecember
Date : 2019.11.16
原文

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者毡鉴。
  • 序言:七十年代末崔泵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子猪瞬,更是在濱河造成了極大的恐慌憎瘸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陈瘦,死亡現(xiàn)場離奇詭異幌甘,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門锅风,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酥诽,“玉大人,你說我怎么就攤上這事皱埠∨杈” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵漱逸,是天一觀的道長泪姨。 經(jīng)常有香客問我,道長饰抒,這世上最難降的妖魔是什么肮砾? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮袋坑,結果婚禮上仗处,老公的妹妹穿的比我還像新娘。我一直安慰自己枣宫,他們只是感情好婆誓,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著也颤,像睡著了一般洋幻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翅娶,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天文留,我揣著相機與錄音,去河邊找鬼竭沫。 笑死燥翅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蜕提。 我是一名探鬼主播森书,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谎势!你這毒婦竟也來了凛膏?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤它浅,失蹤者是張志新(化名)和其女友劉穎译柏,沒想到半個月后镣煮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姐霍,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了镊折。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胯府。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖恨胚,靈堂內(nèi)的尸體忽然破棺而出骂因,到底是詐尸還是另有隱情,我是刑警寧澤赃泡,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布寒波,位于F島的核電站,受9級特大地震影響升熊,放射性物質發(fā)生泄漏俄烁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一级野、第九天 我趴在偏房一處隱蔽的房頂上張望页屠。 院中可真熱鬧,春花似錦蓖柔、人聲如沸辰企。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牢贸。三九已至,卻和暖如春镐捧,著一層夾襖步出監(jiān)牢的瞬間十减,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工愤估, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帮辟,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓玩焰,卻偏偏與公主長得像由驹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子昔园,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容