C#中委托、事件和回調(diào)的使用及說明
委托是一個(gè)類,它定義了方法的類型,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時(shí)使得程序具有更好的可擴(kuò)展性。
事件是對(duì)委托的封裝。如果不進(jìn)行封裝,讓委托暴露給調(diào)用者,調(diào)用者就可以把委托變量重新引用到新的委托對(duì)象,也就刪除了當(dāng)前要調(diào)用的方法列表;
定義一個(gè)事件有兩步,首先定義一個(gè)委托,它包括了這件事的“協(xié)議”和委托方法(由誰去做);其次,用event關(guān)鍵字和相關(guān)委托聲明這個(gè)事件。事件像是一個(gè)接口,封裝了委托所定的“協(xié)議”。由于委托已經(jīng)定義了協(xié)議,剩下的就是按這個(gè)協(xié)議去辦事,至于怎么做它并不關(guān)心。調(diào)用者無法訪問委托對(duì)象。
回調(diào)函數(shù)就是把一個(gè)方法的傳給另外一個(gè)方法去執(zhí)行。回調(diào)函數(shù)只是一個(gè)功能片段,由用戶按照回調(diào)函數(shù)的調(diào)用約定來實(shí)現(xiàn)的一個(gè)函數(shù)??梢园讶我庖粋€(gè)符合這個(gè)委托的方法傳遞進(jìn)去,意思就是說這部分代碼是可變的。而設(shè)計(jì)上有一個(gè)抽離出可變部分代碼的原則,這種用法無疑可以用到那種場(chǎng)合了。從上可知,事件和回調(diào)都是對(duì)委托的一種用法。事件是把委托封裝起來,而回調(diào)函數(shù)則是由委托綁定不同的函數(shù)來實(shí)現(xiàn)不同的功能。
委托的使用案例
定義委托和方法
//委托定義(要與方法中參數(shù)一致) public delegate int DelegateTest(int n1, int n2); class Math { //方法定義(委托要執(zhí)行的方法,本案例把方案寫到class類中) public int Multiply(int n1, int n2) { return n1 * n2; } public int AddTest(int n1, int n2) { return n1 + n2; } }
委托的使用
private void button1_Click(object sender, EventArgs e) { Math objMath = new Math(); //創(chuàng)建委托對(duì)象 DelegateTest delegateDemo1; //將方法與委托對(duì)象關(guān)聯(lián)起來 (委托:將方法當(dāng)作另一個(gè)方法的參數(shù)來進(jìn)行傳遞) //delegateDemo1 = new CallDelegate(objMath.Multiply); delegateDemo1 = objMath.Multiply; //與上面方法相同 //delegateDemo1 += objMath.AddTest; //給委托對(duì)象再綁定一個(gè)方法,若該條代碼執(zhí)行,顯示結(jié)果為17 //將委托實(shí)例化 int result = delegateDemo1(5, 12); richTextBox1.AppendText(result.ToString() + "\r"); //****委托的另外一寫法,通過Action或Func,如果有返回值用Func,否則用Action *****// //Func<int, int, int> func1 = new Func<int, int, int>(objMath.Multiply); Func<int, int, int> func1 = objMath.Multiply; richTextBox1.AppendText(func1.Invoke(6, 13) + "\r"); }
執(zhí)行的結(jié)果
利用Action或Func簡(jiǎn)化代碼
private void button4_Click(object sender, EventArgs e) { Math objMath = new Math(); //委托的另外一寫法,通過Action或Func,如果有返回值用Func,否則用Action //Func<int, int, int> func1 = new Func<int, int, int>(objMath.Multiply); //同下 Func<int, int, int> func1 = objMath.Multiply; richTextBox1.AppendText(func1.Invoke(6, 13) + "\r"); }
事件的使用案例
class ClassA { public string ClassAinfo = "A 默認(rèn)!"; public void DispInfo() { ClassAinfo = "A 收到!"; } } class ClassB { public string ClassAinfo = "B 默認(rèn)!"; public void DispInfo() { ClassAinfo = "B 收到!"; } } class DelegatEventTest { //定義委托 public delegate void MyDelegateEventHandler(); //定義事件 public event MyDelegateEventHandler NotifyEveryOne; //調(diào)用事件 public void Notify() { if (NotifyEveryOne != null) { NotifyEveryOne(); } } }
事件的使用
private void button3_Click(object sender, EventArgs e) { //創(chuàng)建classA和classB的對(duì)象 ClassA objA = new ClassA(); ClassB objB = new ClassB(); //創(chuàng)建委托的對(duì)象 DelegatEventTest event1 = new DelegatEventTest(); //訂閱事件(類似于 方法與委托事件的關(guān)聯(lián)) event1.NotifyEveryOne += new DelegatEventTest.MyDelegateEventHandler(objA.DispInfo); //event1.NotifyEveryOne += new DelegatEventTest.MyDelegateEventHandler(objB.DispInfo); event1.Notify(); richTextBox1.AppendText(objA.ClassAinfo + "\r"); richTextBox1.AppendText(objB.ClassAinfo + "\r"); }
帶參數(shù)的事件案例
參考網(wǎng)上的案例,場(chǎng)景:首領(lǐng)boyK要搞一場(chǎng)鴻門宴,吩咐部下boyA和boyB各自帶隊(duì)埋伏在屏風(fēng)兩側(cè),約定以杯為令:若左手舉杯,則boyA帶隊(duì)殺出;若右手舉杯,則boyB帶隊(duì)殺出;若直接摔杯,則boyA和boyB同時(shí)殺出。boyA和boyB襲擊的具體方法,首領(lǐng)boyK并不關(guān)心。
boyK的定義
public class BoyK { //定義委托 public delegate void RaiseEventHandler(string hand); public delegate void FallEventHandler(); //定義事件 public event RaiseEventHandler RaiseEvent; public event FallEventHandler FallEvent; //調(diào)用事件(例:舉手事件) public void Raise(string hand) { if (RaiseEvent!=null) { RaiseEvent(hand); } } //調(diào)用事件(例:摔杯事件) public void Fall() { if (FallEvent!=null) { FallEvent(); } } }
boyA的定義
class BoyA { public string str = "A待命"; BoyK boyk; public BoyA(BoyK k) { boyk = k; k.RaiseEvent += new BoyK.RaiseEventHandler(k_RaiseEvent); //訂閱舉杯事件 k.FallEvent += new BoyK.FallEventHandler(k_FallEvent); //訂閱摔杯事件 } public void Attack() { str = "A開始**"; } //boyK舉杯的動(dòng)作 void k_RaiseEvent(string hand) { if (hand.Equals("左")) { Attack(); } } void k_FallEvent() { Attack(); } }
boyB的定義
class BoyB { public string str = "B待命"; BoyK boyk; public BoyB(BoyK k) { boyk = k; k.RaiseEvent += new BoyK.RaiseEventHandler(k_RaiseEvent); //訂閱舉杯事件 k.FallEvent += new BoyK.FallEventHandler(k_FallEvent); //訂閱摔杯事件 } public void Attack() { str = "B開始**"; } void k_RaiseEvent(string hand) { if (hand.Equals("右")) { Attack(); } } void k_FallEvent() { Attack(); } }
事件的使用
private void button2_Click(object sender, EventArgs e) { BoyK boyK = new BoyK(); BoyA boyA = new BoyA(boyK); BoyB boyB = new BoyB(boyK); //boyK.Raise("左"); boyK.Raise("右"); //boyK.Fall(); richTextBox1.AppendText(boyA.str+"\r"); richTextBox1.AppendText(boyB.str + "\r"); }
運(yùn)行效果
回調(diào)函數(shù)的使用案例
實(shí)際開發(fā)中,下面這個(gè)類會(huì)封裝起來,只提供函數(shù)接口。相當(dāng)于系統(tǒng)底層
//實(shí)際開發(fā)中,下面這個(gè)類會(huì)封裝起來,只提供函數(shù)接口。相當(dāng)于系統(tǒng)底層 class CalculateClass { public delegate int SomeCalculateWay(int num1, int num2); //將傳入?yún)?shù)在系統(tǒng)底層進(jìn)行某種處理,具體計(jì)算方法由開發(fā)者開發(fā),函數(shù)僅提供執(zhí)行計(jì)算方法后的返回值 //下面的代碼中相當(dāng)于調(diào)用了一個(gè)回調(diào)函數(shù) public int Calculate(int num1, int num2, SomeCalculateWay call) { return call(num1, num2); } }
開發(fā)層處理,開發(fā)人員編寫具體的計(jì)算方法
//開發(fā)層處理,開發(fā)人員編寫具體的計(jì)算方法 class FunctionClass { public int GetSum(int a, int b) { return a + b; } public int GetMulti(int a, int b) { return a * b; } }
用戶層,執(zhí)行輸入等操作
private void button4_Click(object sender, EventArgs e) { CalculateClass cc = new CalculateClass(); FunctionClass fc = new FunctionClass(); int result1 = cc.Calculate(2, 3, fc.GetSum); int result2 = cc.Calculate(2, 3, fc.GetMulti); richTextBox1.AppendText(result1 + "\r"); richTextBox1.AppendText(result2 + "\r"); }
說明:上述代碼中的FunctionClass中的GetSum()和GetMulti()兩個(gè)函數(shù)稱為回調(diào)函數(shù)。
可以看到整個(gè)程序中并沒有哪個(gè)地方通過類似GetSum(1,2)這種形式調(diào)用了該函數(shù),只有將其當(dāng)作另一個(gè)函數(shù)的參數(shù)來進(jìn)行調(diào)用。
如cc.PrintAndCalculate(2, 3, fc.GetSum)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#獲取系統(tǒng)當(dāng)前IE版本號(hào)
這篇文章主要為大家詳細(xì)介紹了C#獲取系統(tǒng)當(dāng)前IE版本號(hào),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12C#遞歸方法實(shí)現(xiàn)無限級(jí)分類顯示效果實(shí)例
這篇文章主要介紹了C#遞歸方法實(shí)現(xiàn)無限級(jí)分類顯示效果,結(jié)合完整實(shí)例形式分析了C#遞歸算法與數(shù)據(jù)元素遍歷的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06C#模擬實(shí)現(xiàn)鼠標(biāo)自動(dòng)點(diǎn)擊與消息發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了C#如何利用windows api來模擬實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊、右擊、雙擊以及發(fā)送文本功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-08-08C#中IsNullOrEmpty和IsNullOrWhiteSpace的使用方法及區(qū)別解析
今天我們將探討C#中兩個(gè)常用的字符串處理方法:IsNullOrEmpty和IsNullOrWhiteSpace,本文中,我們將詳細(xì)解釋這兩個(gè)方法的功能和使用場(chǎng)景,并幫助您更好地理解它們之間的區(qū)別,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-07-07C#怎樣實(shí)現(xiàn)文件下載斷點(diǎn)續(xù)傳
這篇文章主要介紹了C#怎樣實(shí)現(xiàn)文件下載斷點(diǎn)續(xù)傳,對(duì)斷點(diǎn)續(xù)傳感興趣的同學(xué),可以參考下2021-04-04