對(duì)c#中托的理解
理解托從一個(gè)簡(jiǎn)單的例子開(kāi)始
public class LoveManager
{
public void Love(string name)
{
Console.WriteLine("我愛(ài)你, {0}", name);
}
}
class Program
{
static void Main(string[] args)
{
LoveManager loveManager = new LoveManager();
loveManager.Love("張曼玉");
}
}
執(zhí)行結(jié)果:
我愛(ài)你, 張曼玉
我留意到后來(lái)電影里出現(xiàn)了外國(guó)客戶,我想代碼應(yīng)該是這樣:
//枚舉,可擴(kuò)展多語(yǔ)種
public enum Language
{
English,
Chinese
}
public class LoveManager
{
public void Love(string name, Language lang)
{
switch (lang)
{
case Language.Chinese:
loveChinese(name);
break;
case Language.English:
loveEnglish(name);
break;
}
}
//漢語(yǔ)客戶專用
public void LoveChinese(string name)
{
Console.WriteLine("我愛(ài)你, {0}", name);
}
//英語(yǔ)客戶專用
public void LoveEnglish(string name)
{
Console.WriteLine("I love you, {0}", name);
}
}
class Program
{
static void Main(string[] args)
{
LoveManager loveManager = new LoveManager();
loveManager.Love("張曼玉", Language.Chinese);
loveManager.Love("Sophie Marceau", Language.English);
}
}
執(zhí)行結(jié)果:
我愛(ài)你, 張曼玉
I love you, Sophie Marceau
OK,現(xiàn)在張曼玉能聽(tīng)懂“我愛(ài)你”,Sophie Marceau能聽(tīng)懂“I love you”。雖然支持了英漢雙語(yǔ)表白,但以后還有法國(guó)客戶,葡萄牙客戶,客戶怎么辦?每擴(kuò)展一個(gè)語(yǔ)種除了添加這個(gè)語(yǔ)種“我愛(ài)你”的方法,還得擴(kuò)展枚舉,擴(kuò)展LoveManager.Love(),確實(shí)有些繁瑣。
C語(yǔ)言時(shí)代:指針
此時(shí),不得不提到C語(yǔ)言中大名鼎鼎的指針。指針允許把一個(gè)函數(shù)的地址作為參數(shù)傳遞給另一個(gè)函數(shù),這個(gè)特性在以后的各種高級(jí)語(yǔ)言中得到了擴(kuò)展和加強(qiáng)。先看如下C代碼:
#include <stdio.h>
//接受一個(gè)指針類型的參數(shù)
void func1(void(*p)(void)){
printf("this is func1\r\n");
//通過(guò)指針調(diào)用函數(shù)
p();
}
void func2(){
printf("this is func2\r\n");
}
int main() {
//將func2地址作為參數(shù)傳遞
func1(func2);
return 0;
}
執(zhí)行結(jié)果:
this is func1
this is func2
在.Net中能不能像C語(yǔ)言一樣,把函數(shù)作為一個(gè)參數(shù)傳遞并且調(diào)用呢?
//這段代碼并不能被執(zhí)行,但如果在.Net中可以這樣寫(xiě)的話問(wèn)題就會(huì)簡(jiǎn)單很多 Love("張曼玉", LoveChinese);
Love("Sophie Marceau", LoveEnglish);
.Net中更完美的解決方案:托
在.Net中不但可以像C語(yǔ)言一樣將函數(shù)作為參數(shù)傳遞,并且.Net提供了類型安全機(jī)制和更加強(qiáng)大的功能,如下提供了使用托的完整代碼示例:
using System;
namespace DelegateDemo
{
//定義托
public delegate void LoveDelegate(string name);
public class LoveManager
{
public void Love(string name, LoveDelegate loveDelegate)
{
loveDelegate(name);
}
//漢語(yǔ)客戶專用
public void LoveChinese(string name)
{
Console.WriteLine("我愛(ài)你, {0}", name);
}
//英語(yǔ)客戶專用
public void LoveEnglish(string name)
{
Console.WriteLine("I love you, {0}", name);
}
}
class Program
{
static void Main(string[] args)
{
LoveManager loveManager = new LoveManager();
loveManager.Love("張曼玉", loveManager.LoveChinese);
loveManager.Love("Sophie Marceau", loveManager.LoveEnglish);
}
}
}
執(zhí)行結(jié)果:
我愛(ài)你, 張曼玉
I love you, Sophie Marceau
定義托
public delegate void LoveDelegate(string name);
我們現(xiàn)在對(duì)托做一個(gè)總結(jié):
托是一個(gè)類,它定義了方法的類型,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來(lái)進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語(yǔ)句,同時(shí)使得程序具有更好的可擴(kuò)展性。
在C#中托使用特有的關(guān)鍵字 delegate 來(lái)定義,在delegate之后緊跟的是函數(shù)簽名。為了確保類型安全,.Net中的托要求函數(shù)具有相同的簽名,比如 func(int p) 和func(string p)不能使用同一個(gè)托,因?yàn)樗鼈兊膮?shù)類型不一樣。
通過(guò)ILDasm.exe可以發(fā)現(xiàn),定義托的那行代碼實(shí)際在編譯時(shí)會(huì)自動(dòng)生成一個(gè)類,如果要還原這個(gè)類,代碼是這樣:
public class LoveDelegate : System.MulticastDelegate
{
//構(gòu)造器
public LoveDelegate(Object obj, IntPtr method);
//原型
public virtual void Invoke(string name);
//異步回調(diào)
public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object obj);
public virtual void EndInvoke(IAsyncResult result);
}
因此,托實(shí)際上就是一個(gè)類,它繼承至System.MulticastDelegate,凡是可以定義類的地方,都可以定義托。
托的構(gòu)造函數(shù)
LoveManager loveManager = new LoveManager();
//編譯不能通過(guò),托必須使用帶有一個(gè)參數(shù)的構(gòu)造函數(shù)
//LoveDelegate loveDelegate = new LoveDelegate();
LoveDelegate loveDelegate = new LoveDelegate(loveManager.LoveChinese);
loveDelegate("吳劍");
與類不同的是,托必須使用帶有一個(gè)參數(shù)的構(gòu)造函數(shù)。
托推斷語(yǔ)法
LoveManager loveManager = new LoveManager();
//等同于:LoveDelegate loveDelegate = new LoveDelegate(loveManager.LoveChinese);
LoveDelegate loveDelegate = loveManager.LoveChinese;
loveDelegate("吳劍");
托與方法進(jìn)行綁定
回到上面的例子,有一天一富二代找到小金,說(shuō)錢不是問(wèn)題,你去張曼玉樓下,用中文喊一遍,再用英文喊一遍。
static void Main(string[] args)
{
LoveManager loveManager = new LoveManager();
//定義托變量
LoveDelegate delegate1;
//變量初始化(用中文喊一遍)
delegate1 = loveManager.LoveChinese;
//綁定方法(用英文再喊一遍)
delegate1 += loveManager.LoveEnglish;
delegate1("張曼玉");
}
執(zhí)行結(jié)果:
我愛(ài)你, 張曼玉
I love you, 張曼玉
我們可以用 += 將多個(gè)方法綁定到一個(gè)托,也可以使用 -= 移除方法與托的綁定。
匿名方法
客戶的需求總是千變?nèi)f化,一個(gè)客戶跟小金說(shuō),我要跟曼玉表白,除了用中英文,能不能后面再給我加一句,曼玉一聽(tīng)到這句準(zhǔn)會(huì)答應(yīng)我。
LoveManager loveManager = new LoveManager();
LoveDelegate loveDelegate = loveManager.LoveEnglish;
loveDelegate += loveManager.LoveChinese;
loveDelegate += delegate(string name)
{
Console.WriteLine("{0}, 還記得大明湖畔的夏雨荷嗎?", name);
};
loveDelegate("曼玉");
執(zhí)行結(jié)果:
I love you, 曼玉
我愛(ài)你,曼玉
曼玉,還記得大明湖畔的夏雨荷嗎?
針對(duì)這位特殊客戶使用了匿名方法,不是每個(gè)人示愛(ài)的時(shí)候都會(huì)提到大明湖畔的夏雨荷,也就是這位特殊客戶使用一次而以,所以沒(méi)有必要定義一個(gè)方法。使用匿名方法可以減少編碼量,降低代碼復(fù)雜度。
Lambda(λ)表達(dá)式
C# 3.0為匿名方法提供了Lambda表達(dá)式,如下代碼執(zhí)行結(jié)果與上面的示例完全一致:
LoveManager loveManager = new LoveManager();
LoveDelegate loveDelegate = loveManager.LoveEnglish;
loveDelegate += loveManager.LoveChinese;
//用紅色字體標(biāo)出了Lambda表達(dá)式部分loveDelegate += name =>
{
Console.WriteLine("{0}, 還記得大明湖畔的夏雨荷嗎?", name);
};
loveDelegate("曼玉");
=>為L(zhǎng)ambda運(yùn)算符,運(yùn)算符左邊列出匿名方法需要的參數(shù),可以這樣使用:
(string param1, int param2)
也可以:
(param1, param2)
如示例代碼只有一個(gè)參數(shù)還可以去掉括號(hào):
param1
Lambda表達(dá)式右邊為匿名方法實(shí)現(xiàn)代碼,如果實(shí)現(xiàn)代碼只有一行,還可以刪除花括號(hào)和return語(yǔ)句,因?yàn)榫幾g器會(huì)自動(dòng)添加。
共同學(xué)習(xí),共同進(jìn)步!
相關(guān)文章
C#中BitmapImage與BitmapSource接口的區(qū)別對(duì)比小結(jié)
BitmapImage和BitmapSource都可以用于表示和顯示圖像,本文就來(lái)介紹一下C#中BitmapImage與BitmapSource接口的區(qū)別對(duì)比,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03C#使用CallContext緩存線程數(shù)據(jù)
這篇文章介紹了C#使用CallContext緩存線程數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05C# 如何設(shè)置label(標(biāo)簽)控件的背景顏色為透明
這篇文章主要介紹了C# 如何設(shè)置label(標(biāo)簽)控件的背景顏色為透明,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-10-10C#實(shí)現(xiàn)char字符數(shù)組與字符串相互轉(zhuǎn)換的方法
這篇文章主要介紹了C#實(shí)現(xiàn)char字符數(shù)組與字符串相互轉(zhuǎn)換的方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了C#字符數(shù)組轉(zhuǎn)字符串及字符串轉(zhuǎn)字符數(shù)組的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-02-02對(duì)WPF中的TreeView實(shí)現(xiàn)右鍵選定
這篇文章介紹了WPF實(shí)現(xiàn)右鍵選定TreeView的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06Unity調(diào)用C++?dll實(shí)現(xiàn)打開(kāi)雙目相機(jī)
這篇文章主要為大家詳細(xì)介紹了如何在Unity中調(diào)用C++?dll實(shí)現(xiàn)打開(kāi)雙目相機(jī)的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-05-05