C#的委托Delegate


一、委托基礎

  1.什么是委托

  委托(Delegate) 是存有對某個方法的引用的一種引用類型變量,用關鍵字delegate申明,實現相同返回值和參數的函數的動態調用,提供了對方法的抽象。

  委托(Delegate)特別用於實現事件回調方法。所有的委托(Delegate)都派生自 System.Delegate 類。

 

  2.聲明委托

  委托聲明后決定了該委托可以引用的方法。

   public delegate string MyDelegate(int i);

  上面聲明的委托可以用於引用任何返回值為string類型並且參數為一個int類型的任意方法名的方法,例如下面這個:

  public static string GetStr(int i){return i.ToString();}

  所以委托的聲明格式為:訪問修飾符+delegate+返回類型+類型名+參數。

 

  3.初始化委托變量以及賦值

  聲明了委托類型后,和string、int等類型一樣需要聲明變量才能使用。對於初始化變量的賦值有兩種方式:

  (1)new實例化賦值

  和一般的類實例化一樣,在構造函數中傳入方法名即可。

  MyDelegate mydelegate = new MyDelegate(GetStr);

  (2)直接賦值

  由於方法名稱和相應的委托之間存在隱身轉換,所以可以等於號賦值。

  MyDelegate mydelegate = GetStr;

  以上例子都是直接將方法名賦值給委托變量的,這是因為方法由static修飾。對於非靜態的變量還是需要實例化使用,如下:

  MyDelegate mydelegate = new People().GetStr;

  由於委托是引用類型,用 '=' 重新賦值后會改變方法的引用地址,下述例子也繼續使用靜態方法。

 

  4.多播委托

  委托對象可以通過 ‘+’ 運算法進行組合,一個合並委托調用所組合的委托的所有指向方法引用地址,合並的委托必須是相同類型的。不僅是對象可以組合,通過 '+' 運算符可以讓委托變量對方法自增。

  (1)委托對象組合

  MyDelegate mydelegate1 = GetStr;
  MyDelegate mydelegate2 = GetStr;
  MyDelegate mydelegate3 = mydelegate1 + mydelegate2;

  (2)自增

  MyDelegate mydelegate = GetStr;
  mydelegate += GetStr;

  有增自然有減,可以通過 ‘-’ 運算符進行方法引用地址的剔除,如果有多個同樣的方法,只刪除其中一個。

 

  5.匿名方法

  我們之前的方法都是事先聲明好了的,然后使用方法名。但是有時候我們不想要聲明新方法,因為這個是一個臨時的方法。那么就可以用在c# 2.0版本引入的匿名方法,或者是3.0以后版本的lambda表達式。

  匿名方法使用的也是delegate關鍵字,不需要定義返回類型,格式為: delegate (傳入參數) {執行語句},如下:

  MyDelegate mydelegate = delegate(int i) { return i.ToString(); };

   lambda表達式簡化了匿名方法的書寫,去掉了delegate關鍵字並加入 '=>' 運算符:

  MyDelegate mydelegate = (int i) => { Console.WriteLine(i.ToString()); };

 

  6.委托調用

  委托的調用和方法的調用差不多,因為委托聲明的時候參數和返回值都已經確定了,所有加入委托調用列表的方法都是一樣的,所以當委托調用的時候所有方法會依次執行。多播委托的情況下會返回最后一個有返回值的方法結果。但是要注意委托變量是否為空,空的執行會報錯。

  if(mydelegate != null)
      mydelegate(1);

 

  7.泛型委托 

  泛型委托的加入使委托的使用更加方便,簡化我們的代碼。常用的泛型委托有兩種:Action和Func,他們的使用和一般的委托差不多,幫我們省去了聲明的哪一步。

  Action是無返回值的委托,封裝了從無參數到16個參數的委托。

  Action action1 = () => { Console.WriteLine("無參的情況"); };
  Action
<int> action = (int i) => { Console.WriteLine(i.ToString()); };
  action
+= (int i) => { Console.WriteLine((i+1).ToString()); }; if (action != null)   action(1);

  Func是有返回參數,所以格式是Fun<T t1,.....,TResult result>,這個返回類型為最后一個參數,並且是必須的,傳入參數類型可以沒有,但是返回類型必須要。

    Func<string,string> func = (string str) => { return str; };
    if(func != null)
        Console.WriteLine(func("hahaha"));    

二、委托的應用

  委托的聲明和使用其實不難,但是很大的一個困擾就是不知道什么時候使用,園中有很多委托的文章我看了很多,大家都舉了很多的例子,比如燒開水啥的,但是我覺得還是用實際的例子來說明比較好。可能很多人在工作了幾年后都沒有用過委托。所以,實踐出真知。只有當真正用到的時候才能明白其中的含義。

  這里舉在窗體程序中的跨窗體調用方法的例子。現在有兩個窗體Form1和Form2,分別由一個文本框和一個按鈕。現在通過Form1中的按鈕打開Form2窗體,然后通過Form2窗體中的按鈕點擊更新Form1中文本框的內容。

  Form1窗體的代碼如下:

    private void OpenBtn_Click(object sender, EventArgs e)
    {
        Form2 form2 = new Form2();
        form2.action = this.ModifyName;
        form2.Show();
    }
    private void ModifyName(string name)
    {
        NameTxt.Text = name;
    }  

  Form2窗體的代碼如下:

    public Action<string> action;
    private void ModifyBtn_Click(object sender, EventArgs e)
    {
        ConfirmModify(action);
    }
    private void ConfirmModify(Action<string> action)
    {
        //省略數據庫修改等操作.......
        if (action != null)
          action(ModifyTxt.Text);
    }   

   代碼非常簡單,Form1和Form2中的方法都是私有的,只通過Form2中的委托對象來執行Form1中的私有方法。雖然還有別的方法可以實現這個功能,但是我覺得這個方案是比較好的。

三、總結

  有問題可以留言討論,希望可以給大家帶來幫助,共勉!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM