public delegate void MyDelegate(string str);
委托是一種特殊的類型(class),用途是來實現(xiàn)對一種方法的封裝。在某種事件發(fā)生時,自動調用該方法。好處顯然易見,它使用戶可以自定義自己的方法實現(xiàn),通過封裝,CLR會在相應事件激發(fā)時調用你定義的方法,實現(xiàn)你的功能。
注
1.委托的定義和方法的定義類似,只是在前面加了一個delegate,但委托不是方法,它是一種類型。是一種特殊的類型,看成是一種新的對象類型比較好理解。用于對與該委托有相
同簽名的方法調用。
2.委托相當于C++中的函數(shù)指針,但它是類型安全的。
3.委托是從System.Delegate派生,但不能象定義常規(guī)類型一樣直接從System.Delegate派生,對委托的聲明只能通過上面的聲明格式進行定義。關鍵字delegate通知編譯器這是一
個委托類型,從而在編譯的時候對該類進行封裝,對這一過程C#定義了專門的語法來處理這一過程。
4.不能從一個委托類型進行派生,因為它也是默認sealed的
5.委托即可以對靜態(tài)方法進行調用也可以對實例方法進行調用。
6.每個委托類型包含一個自己的調用列表,當組合一個委托或從一個委托中刪除一個委托時都將產(chǎn)生個新的調用列表。
7.兩個不同類型的委托即使它們有相同的簽名和返回值,但還是兩個不同類型的委托。但其實在使用中可看作是相同的。
委托的比較
C#中對委托定義了兩個操作符 == 和 !=
在以下情況下兩個委托是相等的:
1.當兩個委托都同時為null的時候
2.當兩個委托都不為null時,下列情況下是相等的。
a.當兩個委托的各自的調用列表只含有一個入口點的時候
在下列情況下是相等的
(1) 調用同一對象的同一靜態(tài)方法
(2) 調用同一對象的同一實例方法
b.當兩個委托具有多個入口點時
在下列情況下是相等的
(1)只有當它們調用列表中的調用的方法按順序都一一對應相同的對象及對象的同一方法的時候
如上所述的兩個不同類型的委托但是它們具有相同的簽名和返回值時,只要滿足上述條件的,即使它們類型不同,但比較的結果也是相同的。
委托的異常處理
當調用該委托的方法中發(fā)生了異常時,首先在調用該委托的方法中搜尋catch語句塊。如果沒有,則去該委托調用的方法中去尋找有沒有catch語句塊,這和調用方法發(fā)生異常的處
理是一樣的。
當調用一個為null的委托即委托中列表中不存在調用方法時,將發(fā)生NullRefrenceException
委托的注意點:
當一個委托有多個入口點的時候,調用委托將依該委托的調用列表中的方法的順序依次調用.這些方法共享一個參數(shù)集合,所以當委托有返回值的時候調用完這個委托后的返回值是最
后一個方法的返回值或是有out參數(shù).如果該委托的參數(shù)為ref(引用類型),那么在招待第一個方法的時候如果對這個參數(shù)的值有所改變,那么這個改變將會影響到后面的方法調用.
委托的一個例子
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// 創(chuàng)建一個委托實例,封裝C類的靜態(tài)方法M1
MyDelegate d1 = new MyDelegate(C.M1);
d1("D1"); // M1
// 創(chuàng)建一個委托實例,封裝C類的靜態(tài)方法M2
MyDelegate d2 = new MyDelegate(C.M2);
d2("D2"); // M2
// 創(chuàng)建一個委托實例,封裝C類的實例方法M3
MyDelegate d3 = new MyDelegate(new C().M3);
d3("D3"); // M3
// 從一個委托d3創(chuàng)建一個委托實例
MyDelegate d4 = new MyDelegate(d3);
d4("D4"); // M3
// 組合兩個委托
MyDelegate d5 = d1 + d2;
d5 += d3;
d5("D5"); // M1,M2,M3
// 從組合委托中刪除d3
MyDelegate d6 = d5 - d3;
d6("D6"); // M1,M2
d6 -= d3; // 雖然d6調用列表中已經(jīng)沒有d3了,但這樣只是不可能的移除沒有錯誤發(fā)生
d6("D6"); // M1,M2
d6 -= d6;
//d6("D6"); 此時d6的調用列表為空,d6為null,所以引發(fā)System.NullReferenceException
MyDelegate d7 = new MyDelegate(C1.P1);
d7("D7"); // C1.P1
MyDelegate d8 = new MyDelegate(new C2().P1);
d8("D8"); // C2.P1
}
}
// 聲明一個委托MyDelegate
public delegate void MyDelegate(string str);
public class C
{
public static void M1(string str)
{
Console.WriteLine("From:C.M1: ", str);
}
public static void M2(string str)
{
Console.WriteLine("From:C.M2: ", str);
}
public void M3(string str)
{
Console.WriteLine("From:C.M3: ", str);
}
}
public class C1
{
public static void P1(string str)
{
Console.WriteLine("From:C1.P1: ", str);
}
}
public class C2
{
public void P1(string str)
{
Console.WriteLine("From:C2.P1: ", str);
}
}
}
事件委托
事件概述
事件就是當對象或類狀態(tài)發(fā)生改變時,對象或類發(fā)出的信息或通知。發(fā)出信息的對象或類稱為"事件源",對事件進行處理的方法稱為"接收者",通常事件源在發(fā)出狀態(tài)改變信息時,它
并不知道由哪個事件接收者來處理.這就需要一種管理機制來協(xié)調事件源和接收者,C++中通過函數(shù)指針來完成的.在C#中事件使用委托來為觸發(fā)時將調用的方法提供類型安全的封裝
事件的聲明
1.聲明一個委托
public delegate void EventHandler(object sender, System.EventArgs e);
2.聲明一個事件
public event EventHandler Changed;
3.引發(fā)一個事件
public OnChanged(EnventArgs e)
{
if ( Changed != null)
{
Changed(this,e);
}
}
4.定義事件處理程序
public MyText_OnChanged(Object sender,EventArgs e)
5.訂閱事件(將事件處理程序添加到事件的調用列表中)
myText.Changed += EventHandler(MyText_OnChanged);
下面的一個小例子說明了怎樣定義一個完整的事件機制:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyText myText = new MyText();
// 將事件處理程序添加到事件的調用列表中(即事件布線)
myText.Changed += new MyText.ChangedEventHandler(myText_Changed);
string str = "";
while (str != "quit")
{
Console.WriteLine("please enter a string:");
str = Console.ReadLine();
myText.Text = str;
}
}
// 對Change事件處理的程序
private static void myText_Changed(object sender, EventArgs e)
{
Console.WriteLine("text has been changed :n" ,((MyText)sender).Text);
}
}
public class MyText
{
private string _text = "";
// 定義事件的委托
public delegate void ChangedEventHandler(object sender, EventArgs e);
// 定義一個事件
public event ChangedEventHandler Changed;
// 用以觸發(fā)Change事件
protected virtual void OnChanged(EventArgs e)
{
if (this.Changed != null)
this.Changed(this, e);
}
// Text屬性
public string Text
{
get { return this._text; }
set
{
this._text = value;
// 文本改變時觸發(fā)Change事件
this.OnChanged(new EventArgs());
}
}
}
}