一、委托基礎
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中的私有方法。雖然還有別的方法可以實現這個功能,但是我覺得這個方案是比較好的。
三、總結
有問題可以留言討論,希望可以給大家帶來幫助,共勉!