對(duì)C# 2.0中匿名方法的懷疑區(qū)分
發(fā)表時(shí)間:2024-06-11 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]一、 簡(jiǎn)介 所有的方法都使用一個(gè)來(lái)自于相同集合的元素的子集。在C# 2.0中,可選元素集將會(huì)繼續(xù)增長(zhǎng)。從歷史上看-除了C++內(nèi)聯(lián)方法之外-方法都要求有一個(gè)名字、一個(gè)返回類(lèi)型和一個(gè)方法體。而且可選擇地,方法可以使用存取修飾符和一個(gè)參數(shù)列表。在C# 2.0中,方法名已經(jīng)從必需的變成了可選的。 C#...
一、 簡(jiǎn)介
所有的方法都使用一個(gè)來(lái)自于相同集合的元素的子集。在C# 2.0中,可選元素集將會(huì)繼續(xù)增長(zhǎng)。從歷史上看-除了C++內(nèi)聯(lián)方法之外-方法都要求有一個(gè)名字、一個(gè)返回類(lèi)型和一個(gè)方法體。而且可選擇地,方法可以使用存取修飾符和一個(gè)參數(shù)列表。在C# 2.0中,方法名已經(jīng)從必需的變成了可選的。
C# 2.0(一般就代表.NET)引入了匿名方法。一個(gè)匿名方法可以被用在任何使用代理且該代理被定義為內(nèi)聯(lián)的情況下,它不需要方法名,而具有可選的參數(shù)和一個(gè)方法體。
為了使用匿名方法,你需要了解什么是代理。因此,在我們?cè)敿?xì)討論何時(shí)使用匿名方法以及匿名方法的局限性之前,先讓我們簡(jiǎn)要地回顧一下代理。
二、 代理回顧
匿名方法對(duì)于聲明和使用代理來(lái)說(shuō)是一種壓縮方式(如果你對(duì)什么是代理還有疑問(wèn),請(qǐng)繼續(xù)閱讀;否則,可以跳過(guò)下面的這一部分)。代理,作為一種指向函數(shù)簽名的指針,在.NET語(yǔ)言之前的語(yǔ)言中就已存在。切記,在計(jì)算機(jī)中一切其實(shí)都是位和字節(jié)。通過(guò)引入函數(shù)指針技術(shù),有可能動(dòng)態(tài)地把一些未來(lái)的目前尚未知的函數(shù)賦給指針,并由此誕生了事件。
函數(shù)指針的基本使用方法是,可以把一個(gè)函數(shù)的地址賦給一個(gè)單一的指針。為了通過(guò)一個(gè)指針來(lái)調(diào)用該函數(shù),程序員要對(duì)之進(jìn)行檢查以決定是否這個(gè)指針為null,然后間接地通過(guò)這個(gè)指針調(diào)用這個(gè)函數(shù)。總之,要使用指針,必須進(jìn)行null檢查,而現(xiàn)在"一個(gè)指針對(duì)應(yīng)一個(gè)函數(shù)"作為一種限制也該到結(jié)束的時(shí)候了。
回顧一下來(lái)分析,代理會(huì)成為原始函數(shù)指針的下一個(gè)進(jìn)化替代者。一個(gè)代理即是一個(gè)類(lèi),它對(duì)該指針進(jìn)行了封裝;隱含地,.NET中的代理是multicast代理。作為一個(gè)multicast代理僅僅意味著不再存在"一個(gè)函數(shù)對(duì)應(yīng)一個(gè)指針"的限制,因?yàn)閙ulticast代理類(lèi)包含一個(gè)指針列表。包含一個(gè)內(nèi)部列表意味著多于一個(gè)函數(shù)的地址可以被賦值給一個(gè)單一的代理。當(dāng)該代理-你可以認(rèn)為是"事件"-被激發(fā)或調(diào)用時(shí),所有的內(nèi)部列表函數(shù)被調(diào)用。
注意 在C#中,我們調(diào)用代理的方式就象從前我們調(diào)用方法以及調(diào)用所有的賦值函數(shù)一樣;但是我們?nèi)匀荒軌蜻M(jìn)行null檢查。在Visual Basic.NET中,null檢查隱含在激活事件行為中。
在C#中,函數(shù)地址通過(guò)使用一個(gè)重載的+=操作符插入到一個(gè)列表中并且經(jīng)由一個(gè)重載的-=操作符而被刪除。C#還支持手工地定義添加和刪除塊;添加和刪除對(duì)于代理恰似get和set對(duì)于屬性。
在C# 1.0和C# 1.1中,典型情況下,我們把代理實(shí)例賦給事件屬性。例如,在WinForms中,一個(gè)Button控件暴露一個(gè)Click事件。Click的代理類(lèi)型是EventHandler。EventHandler是一個(gè)以對(duì)象和EventArgs為參數(shù)的方法。因此,我們可以用匹配代理EventHandler的簽名的任何方法來(lái)初始化一個(gè)EventHandler對(duì)象并且把代理賦給Click。下面是該代碼看上去的樣子:
private void Form1_Load(object sender, EventArgs e)
{ button1.Click += new EventHandler(OnClick);}
private void OnClick(object sender, EventArgs e)
{ Debug.WriteLine("button1 clicked");}
因?yàn)閃inForms的表單設(shè)計(jì)器和WebForms的頁(yè)面設(shè)計(jì)器自動(dòng)地添加代理綁定;所以,我們有可能不需要手工式地綁定代理而建立大量的代碼。
三、 匿名方法是內(nèi)聯(lián)代理
通常,當(dāng)我們使用代理時(shí),我們總是有一個(gè)方法。該方法的簽名匹配代理的簽名規(guī)定并且能被用來(lái)初始化一個(gè)代理實(shí)例。匿名方法用于把方法和代理的初始化壓縮到一個(gè)單一的位置。
通過(guò)使用前一節(jié)的例子,我們已看到代理new EventHandler的實(shí)例化是怎樣區(qū)別于用來(lái)初始化該代理的方法OnClick的。這部分代碼能被壓縮成一個(gè)匿名方法:
private void Form1_Load(object sender, EventArgs e){
button1.Click += delegate
{
Debug.WriteLine("button1 clicked");
};
}
為了創(chuàng)建該匿名方法,請(qǐng)注意我們刪除了OnClick的方法頭并且用OnClick的方法體的單詞delegate代替了EventHandler代理的構(gòu)造器。其所導(dǎo)致的結(jié)果行為是相同的。如果我們想使用事件參數(shù),我們通常與代理相關(guān)聯(lián),我們可以在單詞delegate之后添加一可選的參數(shù)列表:
private void Form1_Load(object sender, EventArgs e){
button1.Click += delegate(object s, EventArgs ev)
{ Debug.WriteLine("object is " + s.ToString()); };
}
如果你定義代理參數(shù),它們必須匹配代理類(lèi)型所定義的參數(shù)。例如,Click的類(lèi)型是EventHandler,因此如果參數(shù)存在,它們必須匹配EventHandler的參數(shù)對(duì)象和EventArgs。
匿名方法可以被使用在任何需要使用代理的地方。匿名方法可以使用ref和out參數(shù),但是不能使用全局范圍的reference ref或out參數(shù)。匿名方法不能使用unsafe編碼,并且匿名方法不能以使得分支行為跳出匿名方法的代碼塊的方式來(lái)使用goto,break或continue等語(yǔ)句。
四、 市場(chǎng)調(diào)查結(jié)果
匿名方法是好東西嗎?市場(chǎng)調(diào)查證明匿名方法確實(shí)不錯(cuò),因?yàn)樗鼈兡軌驕p少由于實(shí)例化代理和減少分離方法所導(dǎo)致的代碼開(kāi)銷(xiāo)。而且市場(chǎng)調(diào)查還證明匿名方法增強(qiáng)了可用性和可維護(hù)性。我認(rèn)為良好命名的方法也可以實(shí)現(xiàn)這一點(diǎn)。請(qǐng)看下面的代碼容易維護(hù)嗎?
private void Form1_Load(object sender, EventArgs e)
{
BindClick(delegate { Debug.WriteLine("button1 click"); });
}
private void BindClick(EventHandler handler)
{
button1.Click += handler;
}
在這個(gè)例子中,我們把一個(gè)代理傳遞給一個(gè)方法-通過(guò)把該代理作為一個(gè)匿名方法傳遞。僅是保持圓括號(hào)、分號(hào)和方括號(hào)的順序和個(gè)數(shù)就已令人十分頭疼。
如果引用經(jīng)典示例來(lái)說(shuō)明,那就是匿名方法僅僅是因剔除了線(xiàn)程(它們使用代理)而減少了相應(yīng)的創(chuàng)建代理和方法的開(kāi)銷(xiāo)。這倒是真的,但是線(xiàn)程并不經(jīng)常使用并且想正確使用也非常困難。我在想,要想使代碼更為秘密些而不是更為公開(kāi)些該是多么謹(jǐn)慎的一件事情。
就語(yǔ)言方面來(lái)講,我喜歡方法;但是作為一個(gè)實(shí)際開(kāi)發(fā)中的事物,匿名方法也許僅是微軟的某個(gè)發(fā)明者有點(diǎn)太聰明的一種證明。
五、 總結(jié)
匿名方法是可以存在沒(méi)有名字的方法的證明-它們可以被定義并使用在任何能夠使用代理的地方。代理是事件處理器的包裝器。匿名方法到底有多大的實(shí)用性和普遍使用價(jià)值還有待于進(jìn)一步的實(shí)踐證明。我懷疑,匿名方法將不會(huì)比運(yùn)算符重載有更大的用途,并且其使用也會(huì)少之又少;但是匿名方法現(xiàn)在已是.NET的一部分,所以在閱讀代碼時(shí)能夠識(shí)別出它們來(lái)還是很有必要的。