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