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# 結(jié)合 Javascript 測(cè)試獲取天氣信息
本文將介紹如何使用 C# 并結(jié)合 JavaScript 獲取天氣信息,獲取的數(shù)據(jù)來源于360瀏覽器首頁數(shù)據(jù),對(duì)C# 獲取天氣信息示例代碼感興趣的朋友一起看看吧2024-08-08
10分鐘學(xué)會(huì)Visual Studio將自己創(chuàng)建的類庫打包到NuGet進(jìn)行引用(net,net core,C#)
這篇文章主要介紹了10分鐘學(xué)會(huì)Visual Studio將自己創(chuàng)建的類庫打包到NuGet進(jìn)行引用(net,net core,C#),本文給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
在C#項(xiàng)目中調(diào)用C++編寫的動(dòng)態(tài)庫的三種方式
這篇文章給大家介紹了三種方式詳解如何在C#項(xiàng)目中調(diào)用C++編寫的動(dòng)態(tài)庫,文中通過代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01
C#實(shí)現(xiàn)簡(jiǎn)單成績(jī)管理系統(tǒng)的完整步驟
這篇文章主要給大家介紹了關(guān)于C#實(shí)現(xiàn)簡(jiǎn)單成績(jī)管理系統(tǒng)的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
C#實(shí)現(xiàn)appSettings節(jié)點(diǎn)讀取與修改的方法
這篇文章主要介紹了C#實(shí)現(xiàn)appSettings節(jié)點(diǎn)讀取與修改的方法,是非常實(shí)用的技巧,需要的朋友可以參考下2014-10-10

