出處:http://blog.csdn.net/caoxicao
作者:草惜草
轉載請注明出處
問題四 C# 中的委托是什麼?事件是不是一種委托? 答 : 委托委托是C#中的一種引用類型,類似于C/C++中的函數指針。與函數指針不同的是,委托是面向對象、類型安全的,而且委托可以引用靜态方法和執行個體方法,而函數指針隻能引用靜态函數。委托主要用于 .NET Framework 中的事件處理程式和回調函數。
一個委托可以看作一個特殊的類,因而它的定義可以像正常類一樣放在同樣的位置。與其他類一樣,委托必須先定義以後,再執行個體化。
委托派生于基類System.Delegate,不過委托的定義和正常類的定義方法不太一樣。委托的定義通過關鍵字delegate來
定義:
public
delegateint myDelegate(int x,int y);
上面的代碼定義了一個新委托,它可以封裝任何傳回為int,帶有兩個int類型參數的方法。任何一個方法無論是執行個體方法還是靜态方法,隻要他們的簽名(參數類型在一個方法中的順序)和定義的委托是一樣的,都可以把他們封裝到委托中去。
産生委托執行個體和産生類執行個體(對象)差不多,假如我們有如下的方法:
public int sub(int x,int y){
return(x+y);
}
我們就可以使用如下的代碼得到一個
委托執行個體:
myDelegate
calculatin=new myDelegate(sub);
//呵呵,用方法名!!!
接下來我們就可以直接使用calculation調用sub方法了:
calculation(10,3);
當然也可以建立
委托數組,如下就建立了一個委托數組Calculation[]
接下來我們就可以直接使用calculation調用sub方法了:
calculation(10,3);
當然也可以建立
委托數組,如下就建立了一個委托數組Calculation[]
接下來我們就可以直接使用calculation調用sub方法了:
calculation(10,3);
當然也可以建立
委托數組,如下就建立了一個委托數組Calculation[]
private delegate int Calculation(int a, int b);
private static Calculation[] myCalculation=new Calculation[2];
此時,可以用委托數組中的成員來封裝待委托方法,實作建立委托執行個體.
如:
myCalculation[0]=new Calculation(MathClass.max); // 方法名
myCalculation[1]=new Calculation(MathClass.min); // 方法名
這樣,也就可以用建立的委托執行個體數組,來直接調用方法了.
事件在C#中,委托的最基本的一個用處就是用于事件處理。是對象發送的消息,以發信号通知操作的發生,通俗一點講,事件就是程式中産生了一件需要處理的信号。
事件的定義用關鍵字event聲明,不過聲明事件之前必須存在一個多路廣播委托(一個委托同時委托多個方法):
public delegate void Calculate(int x,int y);//傳回值為void的委托自動成為多路廣播委托;
public event Calculate OnCalculate;
可以看出,事件的聲明僅僅是比委托執行個體的聲明多了個關鍵字event,事實上
事件可以看作是一個為事件處理過程定制的多路廣播委托。是以,定義了事件後,我們就可以通過向事件中
操作符 +=添加方法實作事件的預定或者是通過
操作符 -=取消一個事件,這些都與委托執行個體的處理是相同的。
下面再單獨談談
事件代理的相關概念及其應用:
我們就一起來模仿一個Button類及Button值改變後引發事件并執行自定義的ButtonTextChangeEvent事件處理函數的過程,進而以事件資料得到該Button指派過多少次。
Using System;
namespace MyServerControlTest {
public delegate void ButtonTextChangeEventHander ( object sender , EventArgs e ); //事件委托的聲明。
public class Button {
public event ButtonTextChangeEventHander TxtChange;//定義一個事件委托的引用,以備外部進行事件的綁定.
private string _Text;;
public string Text {
get { return _Text;; }
set {
_Text = value;;
System.EventArgs e = new EventArgs();; //這裡是事件的基類執行個體.
ChangeTxt(e);; //調用事件處理函數.
}
}
private void ChangeTxt(EventArgs e) { //事件處理函數.
if( TxtChange != null )
TxtChange(this,e);;//真正調用外部指派的處理函數.
}
}
}
為什麼要這樣定義委托聲明:
delegate ButtonTextChangeEventHander (Object sender , EventArgs e )
原因也很簡單,為了符合.net framework CLS的約定
Sender :引發事件的對象 ; e:事件所帶的資料,而之是以用EventArgs e 是因為這裡的事件是無資料的,如果自定義具有資料的事件的話,還是要從System.EventArgs基類中繼承。
需要指出的是:
if( TxtChange != null )
TxtChange(this,e);;
如果不加 if( TxtChange != null )
那麼當TxtChange并沒有綁定事件處理函數時,它将會引發“未将對象引用到執行個體”的Exception。
/** 〈summary〉
/// 事件處理類
/// 〈/summary〉
public class DelegateDemo {
//定義一個執行個體
private Button button;
public DelegateDemo(){
InitializeComponent();
//構造函數調用時,就開始操作button進行指派。
SetValues();
}
public void InitializeComponent(){
button = new Button();;
//對button對象的TxtChange事件引用,進行事件與處理函數的綁定。
//前面已經說過了,EventHandler是一個類,是以要用new進行建立它的執行個體,其主要是把button_TxtChange事件處理函數的位址傳至這個委托執行個體。
button.TxtChange
+=new ButtonTextChangeEventHander(button_TxtChange);;
}
public void SetValues() {
string[] values = {"AAA","BBB","CCC","DDD","EEE"};;
for( int i = 0;; i 〈 5;; i++ ) {
//進行指派,進而引發事件而直接調用button_TxtChange事件處理函數。
button.Text = values[i];;
}
}
private void button_TxtChange(object sender, System.EventArgs e) {
Console.WriteLine( " Button執行個體新值。其值為:" + ((Button)sender).Text );
}
}
public class MyMain {
public static void Main() {
DelegateDemo delegateDemo = new DelegateDemo();;
Console.Read();;
}
}
}
感覺還是講的不是很清楚。再來看一個:
public class MyObject
{
public delegate void ClickHandler(object sender, EventArgs e);
public event ClickHandler Click;
protected void OnClick()
{
if (Click != null)
Click(this, null);
}
}
ClickHandler 代理使用事件代理的标準模式來定義事件的簽名。其名稱的末尾是處理程式,它帶有兩個參數。第一個參數是發送對象的對象,第二個參數用于傳遞事件的伴随資訊。這種情況下沒有要傳遞的資訊,是以直接使用 EventArgs,但是如果有資料要傳遞,則使用從 EventArgs 派生的類(例如 MouseEventArgs)。
“Click”事件的聲明執行兩項操作:首先,它聲明一個名為“Click”的代理成員變量,該變量從類的内部進行使用。其次,它聲明一個名為“Click”的事件,該事件可按照正常通路規則從類的外部進行使用。
通常,将包括 OnClick() 等函數,以便使類型或派生類型能夠觸發事件。由于“Click”是代理,您将會注意到,用來觸發事件的代碼與代理的代碼相同。
與代理類似,我們使用 += 和 -= 來挂接到事件或解除事件挂接,但與代理不同的是,僅可對事件執行這些操作。這可確定不會發生先前所讨論的兩種錯誤。
使用事件是一種直截了當的方法。
class Test
{
static void ClickFunction( object sender, EventArgs args)
{
// process the event here.
}
public static void Main()
{
MyObject myObject = new MyObject();
myObject.Click += new MyObject.ClickHandler(ClickFunction);
}
}
我們建立一個與代理簽名相比對的靜态函數或成員函數,然後用 += 向事件中添加代理的一個新執行個體