C#中的delegate委托類型基本學(xué)習(xí)教程
委托
delegate 是表示對具有特定參數(shù)列表和返回類型的方法的引用的類型。在實(shí)例化委托時,你可以將其實(shí)例與任何具有兼容簽名和返回類型的方法相關(guān)聯(lián)。你可以通過委托實(shí)例調(diào)用方法。
委托用于將方法作為參數(shù)傳遞給其他方法。事件處理程序就是通過委托調(diào)用的方法。你可以創(chuàng)建一個自定義方法,當(dāng)發(fā)生特定事件時,某個類(如 Windows 控件)就可以調(diào)用你的方法。下面的示例演示了一個委托聲明:
public delegate int PerformCalculation(int x, int y);
可將任何可訪問類或結(jié)構(gòu)中與委托類型匹配的任何方法分配給委托。該方法可以是靜態(tài)方法,也可以是實(shí)例方法。這樣便能通過編程方式來更改方法調(diào)用,還可以向現(xiàn)有類中插入新代碼。
注意:在方法重載的上下文中,方法的簽名不包括返回值。但在委托的上下文中,簽名包括返回值。換句話說,方法和委托必須具有相同的返回類型。
將方法作為參數(shù)進(jìn)行引用的能力使委托成為定義回調(diào)方法的理想選擇。例如,對比較兩個對象的方法的引用可以作為參數(shù)傳遞到排序算法中。由于比較代碼在一個單獨(dú)的過程中,因此可通過更常見的方式編寫排序算法。
委托概述
委托具有以下屬性:
- 委托類似于 C++ 函數(shù)指針,但它們是類型安全的。
- 委托允許將方法作為參數(shù)進(jìn)行傳遞。
- 委托可用于定義回調(diào)方法。
- 委托可以鏈接在一起;例如,可以對一個事件調(diào)用多個方法。
- 方法不必與委托類型完全匹配。
- C# 2.0 版引入了匿名方法的概念,此類方法允許將代碼塊作為參數(shù)傳遞來代替單獨(dú)定義的方法。C# 3.0 引入了 Lambda 表達(dá)式,利用它們可以更簡練地編寫內(nèi)聯(lián)代碼塊。匿名方法和 Lambda 表達(dá)式(在某些上下文中)都可編譯為委托類型。這些功能現(xiàn)在統(tǒng)稱為匿名函數(shù)。
使用委托
委托是安全封裝方法的類型,類似于 C 和 C++ 中的函數(shù)指針。與 C 函數(shù)指針不同的是,委托是面向?qū)ο蟮摹㈩愋桶踩暮涂煽康?。委托的類型由委托的名稱確定。以下示例聲明名為 Del 的委托,該委托可以封裝采用字符串作為參數(shù)并返回 void 的方法:
public delegate void Del(string message);
委托對象通常通過提供委托將封裝的方法的名稱或使用匿名方法構(gòu)造。對委托進(jìn)行實(shí)例化后,委托會將對其進(jìn)行的方法調(diào)用傳遞到該方法。調(diào)用方傳遞到委托的參數(shù)將傳遞到該方法,并且委托會將方法的返回值(如果有)返回到調(diào)用方。這被稱為調(diào)用委托。實(shí)例化的委托可以按封裝的方法本身進(jìn)行調(diào)用。例如:
// Create a method for a delegate. public static void DelegateMethod(string message) { System.Console.WriteLine(message); } // Instantiate the delegate. Del handler = DelegateMethod; // Call the delegate. handler("Hello World");
委托類型派生自 .NET Framework 中的 Delegate 類。委托類型是封裝的,它們不能派生出其他類,也不能從 Delegate 派生出自定義類。由于實(shí)例化的委托是一個對象,因此可以作為參數(shù)傳遞或分配給一個屬性。這允許方法作為參數(shù)接受委托并在稍后調(diào)用委托。這被稱為異步回調(diào),是在長進(jìn)程完成時通知調(diào)用方的常用方法。當(dāng)以這種方式使用委托時,使用委托的代碼不需要知道要使用的實(shí)現(xiàn)方法。功能類似于封裝接口提供的功能。
回調(diào)的另一個常見用途是定義自定義比較方法并將該委托傳遞到短方法。它允許調(diào)用方的代碼成為排序算法的一部分。以下示例方法使用 Del 類型作為參數(shù):
public void MethodWithCallback(int param1, int param2, Del callback) { callback("The number is: " + (param1 + param2).ToString()); }
然后,你可以將上面創(chuàng)建的委托傳遞到該方法:
MethodWithCallback(1, 2, handler);
并將以下輸出接收到控制臺:
The number is: 3
以抽象方式使用委托時,MethodWithCallback 不需要直接調(diào)用控制臺,記住,其不必設(shè)計(jì)為具有控制臺。 MethodWithCallback 的作用是簡單準(zhǔn)備字符串并將字符串傳遞到其他方法。由于委托的方法可以使用任意數(shù)量的參數(shù),此功能特別強(qiáng)大。
當(dāng)委托構(gòu)造為封裝實(shí)例方法時,委托將同時引用實(shí)例和方法。委托不知道除其所封裝方法以外的實(shí)例類型,因此委托可以引用任何類型的對象,只要該對象上有與委托簽名匹配的方法。當(dāng)委托構(gòu)造為封裝靜態(tài)方法時,委托僅引用方法。請考慮以下聲明:
public class MethodClass { public void Method1(string message) { } public void Method2(string message) { } }
加上之前顯示的靜態(tài) DelegateMethod,我們現(xiàn)在已有三個 Del 實(shí)例可以封裝的方法。
調(diào)用時,委托可以調(diào)用多個方法。這被稱為多播。若要向委托的方法列表(調(diào)用列表)添加其他方法,只需使用加法運(yùn)算符或加法賦值運(yùn)算符(“+”或“+=”)添加兩個委托。例如:
MethodClass obj = new MethodClass(); Del d1 = obj.Method1; Del d2 = obj.Method2; Del d3 = DelegateMethod; //Both types of assignment are valid. Del allMethodsDelegate = d1 + d2; allMethodsDelegate += d3;
此時,allMethodsDelegate 的調(diào)用列表中包含三個方法,分別為 Method1、Method2 和 DelegateMethod。原有的三個委托(d1、d2 和 d3)保持不變。調(diào)用 allMethodsDelegate 時,將按順序調(diào)用所有三個方法。如果委托使用引用參數(shù),引用將按相反的順序傳遞到所有這三個方法,并且一種方法進(jìn)行的任何更改都將在另一種方法上見到。當(dāng)方法引發(fā)未在方法內(nèi)捕獲到的異常時,該異常將傳遞到委托的調(diào)用方,并且不會調(diào)用調(diào)用列表中的后續(xù)方法。如果委托具有返回值和/或輸出參數(shù),它將返回上次調(diào)用方法的返回值和參數(shù)。若要刪除調(diào)用列表中的方法,請使用減法運(yùn)算符或減法賦值運(yùn)算符(“+”或“+=”)。例如:
//remove Method1 allMethodsDelegate -= d1; // copy AllMethodsDelegate while removing d2 Del oneMethodDelegate = allMethodsDelegate - d2;
由于委托類型派生自 System.Delegate,因此可以在委托上調(diào)用該類定義的方法和屬性。例如,若要查詢委托調(diào)用列表中方法的數(shù)量,你可以編寫:
int invocationCount = d1.GetInvocationList().GetLength(0);
調(diào)用列表中具有多個方法的委托派生自 MulticastDelegate,該類屬于 System.Delegate 的子類。由于這兩個類都支持 GetInvocationList,因此在其他情況下,上述代碼也將產(chǎn)生作用。
多播委托廣泛用于事件處理中。事件源對象將事件通知發(fā)送到已注冊接收該事件的接收方對象。若要注冊一個事件,接收方需要創(chuàng)建用于處理該事件的方法,然后為該方法創(chuàng)建委托并將委托傳遞到事件源。事件發(fā)生時,源調(diào)用委托。然后,委托將對接收方調(diào)用事件處理方法,從而提供事件數(shù)據(jù)。給定事件的委托類型由事件源確定。有關(guān)詳細(xì)信息,請參閱事件(C# 編程指南)。
在編譯時比較分配的兩個不同類型的委托將導(dǎo)致編譯錯誤。如果委托實(shí)例是靜態(tài)的 System.Delegate 類型,則允許比較,但在運(yùn)行時將返回 false。例如:
delegate void Delegate1(); delegate void Delegate2(); static void method(Delegate1 d, Delegate2 e, System.Delegate f) { // Compile-time error. //Console.WriteLine(d == e); // OK at compile-time. False if the run-time type of f // is not the same as that of d. System.Console.WriteLine(d == f); }
帶有命名方法的委托與帶有匿名方法的委托
委托可以與命名方法關(guān)聯(lián)。使用命名方法對委托進(jìn)行實(shí)例化時,該方法將作為參數(shù)傳遞,例如:
// Declare a delegate: delegate void Del(int x); // Define a named method: void DoWork(int k) { /* ... */ } // Instantiate the delegate using the method as a parameter: Del d = obj.DoWork;
這被稱為使用命名的方法。使用命名方法構(gòu)造的委托可以封裝靜態(tài)方法或?qū)嵗椒?。在早期版本?C# 中,命名方法是對委托進(jìn)行實(shí)例化的唯一方式。但是,在不希望付出創(chuàng)建新方法的系統(tǒng)開銷時,C# 使您可以對委托進(jìn)行實(shí)例化,并立即指定委托在被調(diào)用時將處理的代碼塊。代碼塊可以包含 lambda 表達(dá)式或匿名方法。
備注:作為委托參數(shù)傳遞的方法必須與委托聲明具有相同的簽名。
委托實(shí)例可以封裝靜態(tài)或?qū)嵗椒ā?br />
盡管委托可以使用 out 參數(shù),但建議您不要將其用于多路廣播事件委托,因?yàn)槟鸁o法知道哪個委托將被調(diào)用。
示例 1
以下是聲明及使用委托的一個簡單示例。注意,委托 Del 和關(guān)聯(lián)的方法 MultiplyNumbers 具有相同的簽名
// Declare a delegate delegate void Del(int i, double j); class MathClass { static void Main() { MathClass m = new MathClass(); // Delegate instantiation using "MultiplyNumbers" Del d = m.MultiplyNumbers; // Invoke the delegate object. System.Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); for (int i = 1; i <= 5; i++) { d(i, 2); } // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } // Declare the associated method. void MultiplyNumbers(int m, double n) { System.Console.Write(m * n + " "); } }
輸出:
Invoking the delegate using 'MultiplyNumbers': 2 4 6 8 10
示例 2
在下面的示例中,一個委托被同時映射到靜態(tài)方法和實(shí)例方法,并分別返回特定的信息。
// Declare a delegate delegate void Del(); class SampleClass { public void InstanceMethod() { System.Console.WriteLine("A message from the instance method."); } static public void StaticMethod() { System.Console.WriteLine("A message from the static method."); } } class TestSampleClass { static void Main() { SampleClass sc = new SampleClass(); // Map the delegate to the instance method: Del d = sc.InstanceMethod; d(); // Map to the static method: d = SampleClass.StaticMethod; d(); } }
輸出:
A message from the instance method. A message from the static method.
上一篇:結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件
欄 目:C#教程
本文標(biāo)題:C#中的delegate委托類型基本學(xué)習(xí)教程
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6722.html
您可能感興趣的文章
- 01-10C#中查找Dictionary中的重復(fù)值的方法
- 01-10C#將圖片存放到SQL SERVER數(shù)據(jù)庫中的方法
- 01-10關(guān)于nancy中的身份驗(yàn)證
- 01-10C#中的事務(wù)用法實(shí)例分析
- 01-10C#實(shí)現(xiàn)讀取DataSet數(shù)據(jù)并顯示在ListView控件中的方法
- 01-10C#中的正則表達(dá)式介紹
- 01-10C#開發(fā)中的垃圾回收機(jī)制簡析
- 01-10C#語言中的修飾符匯總
- 01-10C#中的 == 和equals()區(qū)別淺析
- 01-10C#基于委托實(shí)現(xiàn)多線程之間操作的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 04-02jquery與jsp,用jquery
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢data目錄下的sessions文件夾有什