C# 的Delegate(委托)
C# 是一個(gè)頗具爭(zhēng)議的新興語(yǔ)言,由 Microsoft 開發(fā)創(chuàng)造,以作為其 Visual Studio.NET 的基石,目前正處于第一個(gè) Beta 版的發(fā)布階段。C# 結(jié)合了源自 C++ 和 Java 的許多特性。Java 社群對(duì) C# 主要的批評(píng)在于,其聲稱 C# 只是一個(gè)蹩腳的 Java 克隆版本 ——與其說(shuō)它是語(yǔ)言創(chuàng)新的成果,倒不如說(shuō)是一樁訴訟的結(jié)果。而在 C++ 社群里,主要的批評(píng)(也同時(shí)針對(duì) Java)是,C# 只不過(guò)是另一個(gè)泛吹濫捧的私有語(yǔ)言(yet another over-hyped proprietary language)。
本文意在展示一種 C# 的語(yǔ)言特性,而在 C++ 或 Java 中都沒(méi)有直接支持類似的特性。這就是 C# 的 delegate 型別,其運(yùn)作近似于一種指向成員函數(shù)的指針。我認(rèn)為,C# delegate 型別是經(jīng)過(guò)深思熟慮的創(chuàng)新型語(yǔ)言特性,C++ 程序員(無(wú)論其對(duì) C# 或者 Microsoft 有何想法)應(yīng)該會(huì)對(duì)這個(gè)特性產(chǎn)生特殊的興趣。
為了激發(fā)討論,我將圍繞一個(gè) testHarness class 的設(shè)計(jì)來(lái)進(jìn)行闡述。這個(gè) testHarness class 能夠讓任何類別對(duì) static 或 non-static 的 class methods 進(jìn)行注冊(cè),以便后續(xù)予以執(zhí)行。Delegate 型別正是實(shí)現(xiàn) testHarness class 的核心。
C# 的 Delegate Type
Delegate 是一種函數(shù)指針,但與普通的函數(shù)指針相比,區(qū)別主要有三:
1) 一個(gè) delegate object 一次可以搭載多個(gè)方法(methods)[譯注1],而不是一次一個(gè)。當(dāng)我們喚起一個(gè)搭載了多個(gè)方法(methods)的 delegate,所有方法以其“被搭載到 delegate object 的順序”被依次喚起——稍候我們就來(lái)看看如何這樣做。
2) 一個(gè) delegate object 所搭載的方法(methods)并不需要屬于同一個(gè)類別。一個(gè) delegate object 所搭載的所有方法(methods)必須具有相同的原型和形式。然而,這些方法(methods)可以即有 static 也有 non-static,可以由一個(gè)或多個(gè)不同類別的成員組成。
3) 一個(gè) delegate type 的聲明在本質(zhì)上是創(chuàng)建了一個(gè)新的 subtype instance,該 subtype 派生自 .NET library framework 的 abstract base classes Delegate 或 MulticastDelegate,它們提供一組 public methods 用以詢?cè)L delegate object 或其搭載的方法(methods)
聲明 Delegate Type
一個(gè) delegate type 的聲明一般由四部分組成:(a) 訪問(wèn)級(jí)別;(b) 關(guān)鍵字 delegate;(c)返回型別,以及該 delegate type 所搭載之方法的聲明形式(signature);(d) delegate type 的名稱,被放置于返回型別和方法的聲明形式(signature)之間。例如,下面聲明了一個(gè) public delegate type Action,用來(lái)搭載“沒(méi)有參數(shù)并具有 void 返回型別”的方法:
public delegate void Action();
一眼看去,這與函數(shù)定義驚人的相似;唯一的區(qū)別就是多了 delegate 關(guān)鍵字。增加該關(guān)鍵字的目的就在于:要通過(guò)關(guān)鍵字(keyword)——而非字元(token)——使普通的成員函數(shù)與其它形似的語(yǔ)法形式區(qū)別開來(lái)。這樣就有了 virtual,static, 以及 delegate 用來(lái)區(qū)分各種函數(shù)和形似函數(shù)的語(yǔ)法形式。
如果一個(gè) delegate type 一次只搭載單獨(dú)一個(gè)方法(method),那它就可以搭載任意返回型別及形式的成員函數(shù)。然而,如果一個(gè) delegate type 要同時(shí)搭載多個(gè)方法(methods),那么返回型別就必須是 void[譯注2]。 例如,Action 就可以用來(lái)搭載一個(gè)或者多個(gè)方法(method)。在 testHarness class 實(shí)現(xiàn)中,我們就將使用上述的 Action 聲明。
定義 Delegate Handle
在 C# 中我們無(wú)法聲明全局對(duì)象;每個(gè)對(duì)象定義必須是下述三種之一:局部對(duì)象;或者型別的對(duì)象成員;或者函數(shù)參數(shù)列表中的參數(shù)。現(xiàn)在我只向你展示 delegate type 的聲明。之后我們?cè)賮?lái)看如何將其聲明為類別中的成員。
C# 中的 delegate type 與 class, interface, 以及 array types 一樣,屬于 reference type。每個(gè) reference type 被分為兩部分:
- 一個(gè)具名的 句柄(named handle),由我們直接操縱;以及
- 一個(gè)該句柄所屬型別的不具名對(duì)象(unamed object),由我們通過(guò)句柄間接進(jìn)行操縱。必須經(jīng)由 new 顯式的創(chuàng)建該對(duì)象。
?
定義 reference type 是一個(gè)“兩步走”的過(guò)程。當(dāng)我們寫:
Action theAction;
的時(shí)候,theAction 代表“delegate type Action 之對(duì)象”的一個(gè) handle(句柄),其本身并非 delegate object。缺省情況下,它被設(shè)為 null。如果我們?cè)噲D在對(duì)其賦值(譯注:assigned,即與相應(yīng)型別的對(duì)象做attachment)之前就使用它,會(huì)發(fā)生編譯期錯(cuò)誤。例如,語(yǔ)句:
theAction();
會(huì)喚起 theAction 所搭載的方法(method(s))。然而,除非它在定義之后、使用之前被無(wú)條件的賦值(譯注:assigned,即與相應(yīng)型別的對(duì)象做attachment),否則該語(yǔ)句會(huì)引發(fā)編譯期錯(cuò)誤并印出相關(guān)信息。
為 Delegate Object 分配空間
在這一節(jié)中,為了以最小限度的涉及面繼續(xù)進(jìn)行闡述,我們需要訪問(wèn)一個(gè)靜態(tài)方法(static method)和一個(gè)非靜態(tài)方法(non-static method),就此我采用了一個(gè) Announce class。該類別的 announceDate 靜態(tài)方法(static method)以 long form 的形式(使用完整單字的冗長(zhǎng)形式)打印當(dāng)前的日期到標(biāo)準(zhǔn)輸出設(shè)備:
Monday, February 26, 2001
非靜態(tài)方法(non-static method) announceTime 以 short form 的形式(較簡(jiǎn)短的表示形式)打印當(dāng)前時(shí)間到標(biāo)準(zhǔn)輸出設(shè)備:
00:58
前兩個(gè)數(shù)字代表小時(shí),從午夜零時(shí)開始計(jì)算,后兩個(gè)數(shù)字代表分鐘。Announce class 使用了由 .NET class framework 提供的 DateTime class。Announce 類別的定義如下所示。
public class Announce{ public static void announceDate() { DateTime dt = DateTime.Now; Console.WriteLine( "Today's date is {0}", dt.ToLongDateString() ); } public void announceTime() { DateTime dt = DateTime.Now; Console.WriteLine( "The current time now is {0}", dt.ToShortTimeString() ); }}
要讓 theAction 搭載上述方法,我們必須使用 new 表達(dá)式創(chuàng)建一個(gè) Action delegate type(譯注:即創(chuàng)建一個(gè)該類別的對(duì)象)。要搭載靜態(tài)方法,則傳入構(gòu)造函數(shù)的引數(shù)由三部分組成:該方法所屬類別的名稱;方法的名稱;分隔兩個(gè)名稱用的 dot operator(.):
theAction = new Action( Announce.announceDate );
要搭載非靜態(tài)方法,則傳入構(gòu)造函數(shù)的引數(shù)也由三部分組成:該方法所屬的類別對(duì)象名稱;方法的名稱;分隔兩個(gè)名稱用的 dot operator(.):
Announce an = new Announce();theAction = new Action( an.announceTime );
可以注意到, theAction 被直接賦值,事先沒(méi)有做任何檢查(比如,檢查它是否已經(jīng)指代一個(gè)堆中的對(duì)象,如果是,則先刪除該對(duì)象)。在 C# 中,存在于 managed heap(受托管的堆)中的對(duì)象由運(yùn)行期環(huán)境對(duì)其施以垃圾收集動(dòng)作(garbage collected)。我們不需要顯式的刪除那些經(jīng)由 new 表達(dá)式分配的對(duì)象。
在程序的 managed heap(受托管的堆)中,new 表達(dá)式既可以為獨(dú)個(gè)對(duì)象做分配
HelloUser myProg = new HelloUser();
也可以為數(shù)組對(duì)象做分配
string [] messages = new string[ 4 ];
分配語(yǔ)句的形式為:型別的名稱,后跟關(guān)鍵字 new,后跟一對(duì)圓括弧(表示單個(gè)對(duì)象)或者方括號(hào)(表示數(shù)組對(duì)象)[1]。(在 C# 語(yǔ)言設(shè)計(jì)中的一個(gè)普遍特征就是,堅(jiān)持使用單一明晰的形式來(lái)區(qū)別不同的功用。)
轉(zhuǎn)載于:https://www.cnblogs.com/hackpig/archive/2010/02/15/1668355.html
總結(jié)
以上是生活随笔為你收集整理的C# 的Delegate(委托)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: multisim页面不够大_multis
- 下一篇: 【C#】【引用加原创】C#实现kalma