深入理解C#委託及原理

來源:互聯網
上載者:User

一、委託

設想,如果我們寫了一個廚師做菜方法用來做菜,裡面有 拿菜、切菜、配菜、炒菜 四個環節,但編寫此方法代碼的人想讓 配菜 這個環節讓調用方法的人實現,換句話說,就是想在方法被調用時接收代碼 作為參數,在方法中執行這端傳進來的代碼。

但,怎麼為一個方法傳 代碼 進來呢。當然大家想到了傳遞介面方式來實現,咱先不討論介面,因為微軟為我們提供了一個叫做 【委託】 的類型。

 

(一)、委託基礎:

1.       先看看代碼:

(1).定一個方法:void SayHi(string name){Console.WriteLine(“Hi~”+name+”! ” );}

(2).聲明一種委託類型:delegate void DGSayHi(string uName);

(3).建立委託類型對象:DGSayHi dgObj = new DGSayHi(SayHi);//建構函式中傳入了方法

(4).執行委託:
dgObj(“JamesZou”); //調用委託(奇怪:對象加括弧 的方式調用。後面解釋。)
輸出:Hi~JamesZou!

 

2.       什麼是委託。
(1)概念:“C# 中的委託類似於 C 或 C++ 中的函數指標。使用委託使程式員可以將方法引用封裝在委派物件內。然後調用該委派物件就可以執行委派物件內方法引用指向的方法,而不必在編譯時間知道將調用哪個方法(如參數為委託類型的方法,也就是提供了為程式回調指定方法的機制)。”-- 引自MSDN

(2)通俗:就是一個能存放很多方法的指標的調用清單(但方法簽名必須和委託類型簽名一樣),你一調用這個清單,那麼清單裡的所有的指標所對應的方法就會依次被執行。

(3)比方說:有三台機器A、C、D,點一個紅色按鈕就會運行。操作人員接到指令,要求在接到電話後分別開啟AD機器,然後然後工人就在接到電話後,先後開啟AD機器。(此例中的 三台機器就是方法,操作員,就可以看成是“委託”啦)

 

(4)概要圖例:
DGSayHi dgObj = new DGSayHi(SayHi);
dgObj(“James”); //調用委派物件,就會執行委派物件裡的方法。


3.       委託有什麼用。
A.能夠幫程式員在需要時,根據條件動態執行多個方法:(接上例代碼)

(1)定三個方法:
void SayHi(string name){Console.WriteLine(“Hi~”+name ); }
void DaZhaoHu(string name){ Console.WriteLine(“你好啊~”+name ); }
string OHaUo(string name){ Console.WriteLine(“OHaUo ~”+name ); return “JapHi”;}


(2)建立委託類型對象,並通過建構函式傳參方式向委派物件“註冊”第一個方法:
DGSayHi dgObj = new DGSayHi(SayHi);


(3)繼續“註冊兩個方法”:
dgObj+=DaZhaoHu;// (奇怪:對象之間用+=符號來操作。後面解釋)
//dgObj+=OhaUo;//注釋此行代碼,因為編譯時間報錯,OhaUo方法簽名與委託類型的簽名不一致(委託簽名無傳回值)。

 

      (4)執行委派物件:
dgObj(“James”); //執行了此委託中註冊的兩個方法
輸出:
Hi~James
你好啊~James

      
(5)概要圖例


B. 委託作為方法參數(回調方法機制)

(1).接上例代碼,再定義一個方法:
void DoTestDelegateFun(DGSayHi dgObj){dgObj(“鋼鐵俠”);}
(2).調用此方法:
DoTestDelegateFun(SayHi);//輸出:Hi~鋼鐵俠(奇怪:竟然直接傳方法了。後面解釋)

 

      C.委託文法糖

         (1).注意到上面有3個地方我們都覺得“奇怪”:
        a.調用委派物件dgObj(“JamesZou”);
        b.向委託註冊方法 dgObj+=DaZhaoHu;

              c.將方法作為參數 DoTestDelegateFun(SayHi);

         這些用法其實都是FW為我們提供的簡便文法(它們有個可愛的名字:文法糖),在編譯時間由編譯器轉成完整的代碼:
        a. dgObj.Invoke(“JamesZou”);
        b. dgObj = (DGSayHi) Delegate.Combine(dgObj, new DGSayHi(this.DaZhaoHu));

//Combine方法將第二個參數,添加到dgObj中,並返回委派物件。
c. this.DoTestDelegateFun(new DGSayHi(this.SayHi));

         Delegate類、Invoke方法、Combine方法是哪來的呢。


(二)、委託原理

1.delegate 關鍵字

(1).概念:delegate 關鍵字用於聲明一個參考型別,該參考型別可用於封裝命名方法或匿名方法。


(2)編譯後產生的的中間代碼。 
請大家思考一下,關鍵字是類型嗎。不是。那編譯器遇到這個關鍵字做了什麼事情。藉助【IL反組譯工具】 我們來看一看:
a.開始-程式-如圖:
    
b.開啟專案檔夾下的bin\Debug檔案夾,找到程式集 CodeForFun.exe,拖入到【IL反組譯工具】介面中便可看到程式集的IL代碼:
找到我們定義了委託DGSayHi的類DelegateForFun,發現,裡面的 委託型別宣告 代碼
編譯前:delegate string DGSayHi(string uName);
變成了一個類:
   

單擊展開後我們再來看看:

   看出什麼了。
(I).繼承了System.MulticastDelegate。
(II).包含了構造方法、BeginInvoke、EndInvoke、Invoke方法。
也就是說此時,delegate代碼已經編譯成了如下代碼:
編譯後:
class DGSayHi:System.MulticastDelegate 
{
  public DelegateForFun();

     void Invoke(string value);

     IAsyncResult BeginInvoke(string value,AsyncCallback callback,Object object);

     void EndInvoke(IAsyncResult result);

}


(3)System.MulticastDelegate 類

下面我們來看看藉助.Net Reflector工具來查看類庫中的 MulticastDelegate 類

public abstract class MulticastDelegate : Delegate

由此我們可以看出繼承關係:DGSayHi –> MulticastDelegate–> Delegate

MulticastDelegate類中有3個重要的成員,其中兩個繼承自 Delegate  :

a.三者的作用:

_methodPtr 裡儲存的就是 方法指標。

_target 裡用來儲存方法所在的對象。

_invocationList 其實使用時是個object數組,在註冊多個方法時,其他方法就儲存在此成員中,而它也就是 委託鏈 的關鍵容器。

 

          b.概要圖:

          圖中的委派物件 dgObj 在建立時建立了指向方法 SayHi的指標並儲存在 _methodPtr中;_target中儲存了SayHi方法所在的類的對象(比如我把這段代碼寫在表單裡按鈕的點擊方法中,那麼此時 _target就是 SayHi方法所在的表單對象);_invocationList 中儲存了追加的兩個方法的指標,但這兩個方法指標都是分別被裝在 MuticastDelegate對象中。

  轉載請註明出處:ch01.深入理解C#委託及原理 開智網http://www.oumind.com

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.