萬物皆物件!物件與物件之間不僅僅是存在關係,更是具有千絲萬縷的聯絡。關於物件之間的關係,我們在 sql server 中已經討論過。本文要討論的是它們之間存在的聯絡,即:如何使得乙個物件發生變化時,另乙個物件也能隨之發生變化。這種「乙個物件的狀態改變導致其它物件狀態改變」的現象,我們稱之為事件。
在檢視本文所述的內容時,請確定您已經對 c# 的委託機制比較熟練!
定義:事件,是用來描述類的成員發生改變的物件。
我們舉乙個例子,來理解上面的定義:
例如:路邊有一條狗。你看它不爽,於是走上前去踢了它一腳。我們來看緊接著發生的事情:
1、這條狗很膽小,它跑掉了;
2、這條狗是惡狗,它將你反咬一口;
3、這條狗身體瘦弱,經不起你的一腳,一命嗚呼了;
4、……
我想說明的是:在你真正踢它之前,你無法知道它會幹些什麼!在這件事發生之前,這條狗也無法預計你會在什麼時候踢它,它唯一能做的就是「等著被踢」!於是,在封裝 dog 型別的時候,我們不能確定 dog 型別的例項被踢的時機,同時不能確定被踢之後做些什麼!同理,微軟工程師們不論有多麼牛,他們也不能在封裝 button 類的時候確定,你「將」對這個 button 什麼時候,幹些什麼!
使用委託,我們可以解決這個問題。解決問題的思路是:在封裝 button 的時候宣告乙個委託的引用,但是不例項化這個委託,卻又在使用者單擊 button 的時候呼叫這個委託。這樣一來,他們的使用者(button 的使用者),就可以通過首先例項化這個委託的方式來指定當委託被呼叫時需要執行的方法了。
這樣理解起來可能比較複雜,我們來看乙個簡單的例子,然後推測 button 是如何工作的。
首先回到剛才的踢狗事件中。我們來封裝乙個 dog 類。
///// **片斷1
//////
/// 描述狗。為了簡單起見,沒有宣告任何有效的類成員。
///
public class dog
}///
緊接著我們宣告乙個事件成員(實際上是某個委託的乙個引用),在被踢時呼叫這個委託的引用,用於表示被踢的這個瞬間狗的狀態改變。
事先,應該有乙個委託:
public delegate void kickedeventhandler();
使用這個委託,我們在 dog 類中宣告「踢」的事件。並且在描述狗被踢的方法中引發該事件(也就是呼叫委託),以描述狗在這個瞬間狀態發生了變化。
///// **片斷2
//////
/// 描述狗。為了簡單起見,沒有宣告任何有效的類成員。
///
public class dog
}///
1、**1)處,是宣告事件成員的語法。如果不看關鍵字 event ,你會發現:宣告類的事件成員,實際上是宣告了乙個委託型別的引用(變數)。這裡,我們宣告了乙個型別是 kickedeventhandler 的委託型別的變數名叫 kick。
2、引用 kick 尚未例項化。這個例項化的過程,我們將在後面的「訂閱事件」的步驟中進行。訂閱事件的時候才確定這個委託呼叫什麼函式。
3、**2)處,直接呼叫 kick 委託(或者說叫做觸發了事件 kick)。此時此刻,對於編寫 dog 類的我們而言,不能確定使用 dog 類的人想呼叫什麼方法。
以上**,我們完成了事件編寫的兩個步驟:
1、宣告事件
2、呼叫事件
緊接著,我們來看看這個 dog 類怎麼使用。首先編寫乙個 main() 函式,呼叫 dog 類。
///// **片斷3
///class test
}///
我們例項化了「一條狗」。為了能夠使狗在被踢的時候做出響應,我們需要和這條狗有乙個約定:當我踢它時,它應該有點反應。這個過程就是「訂閱事件」。
一旦訂閱了事件,我們和狗就好像有了這個約定。所有其它未訂閱事件的狗,將不會響應我們的「踢」的動作。
///// **片斷4
///class test
private static void dog_kick()
}///
上面的**,有以下說明:
1、**1)處,從語法上說是例項化了乙個 kickedeventhandler 委託型別的物件。回顧委託的執行機制,這行**決不是立即呼叫 dog_kick() 方法。
2、**1)處,使用了委託的引用 dog.kick 指向剛剛例項化的委託物件 new kickedeventhandler(dog_kick)。回顧委託的執行機制,這行**的實際含義是:在將來呼叫 kick 這個委託的時候,編譯器執行 dog_kick 方法。那麼 kick 委託在什麼時候呼叫的呢?請看**片斷2的**2)處的**行。原來,我們只要一呼叫 dog 類的 kicked() 方法,就會呼叫委託 kick (觸發事件實際上就是呼叫委託),一旦呼叫委託,由於先前有「在將來呼叫 kick 這個委託的時候,編譯器執行 dog_kick 方法。」的約定,則方法 dog_kick() 就會執行。
因此,最後一步,我們再具體實現 dog_kick() 方法的方法體,就可以將**在 dog.kick 事件觸發時執行了。
///// **片斷5
///class test
private static void dog_kick()
}///
以上**,我們完成了事件編寫的後兩個步驟:
3、訂閱事件
4、實現事件處理函式
///// **片斷6
//////
/// 在 kick 事件中使用的委託
///
public delegate void kickedeventhandler();
///
/// 描述狗。為了簡單起見,沒有宣告任何有效的類成員。
///
public class dog
}///
/// 測試 dog 類的主類。
///
class test
///
/// 被訂閱到 kick 事件的事件處理程式.
/// 這個函式沒有使用 obj.dog_kick() 的語法呼叫,但是同樣執行了。
/// 這是委託的功勞,由此可見委託在事件機制中的作用。
///
private static void dog_kick()
}///
常是執行上面的**,你會發現:我們通過呼叫 dog 中的 kicked() 方法,導致 test 類中的 dog_kick() 方法被執行。這是不是就是「乙個物件的狀態改變導致其它物件狀態改變」的效果呢?
同理,可以很大膽的推測 button 類中必定包含這樣的**。請讀者自行分析。
///// **片斷6
// 說明:該**片斷只是對事件執行過程的說明,.net framework 中的 system.windows.forms.button 類的封裝實際上要複雜的多。
///public class eventargs
public delegate void eventhandler(object sender, eventargs e);
public class button
}public class testform
private void button_click(object sender, eventargs e)
static void main(string args)
}///
C 中的事件處理
事件 event 是乙個非常重要的概念,我們的程式時刻都在觸發和接收著各種事件 滑鼠點選事件,鍵盤事件,以及處理作業系統的各種事件。所謂事件就是由某個物件發出的訊息。比如使用者按下了某個按鈕,某個檔案發生了改變,socket上有資料到達。觸發事件的物件稱作傳送者 sender 捕獲事件並且做出響應的...
C 中的事件和事件處理
c 中的事件,我覺得和mfc的訊息作用在某些方面是差不多的。這個專案中用到的需求是兩個類之間的資料互動,首先肯定是分為乙個觸發事件的類,乙個處理事件的類。1 首先需要在所有類的外部為事件定義乙個公共訪問型別的 該 為多重 所以 定義方法標識的返回為void型別。一般我們這麼定義 public voi...
C 中的事件處理程式
c 中的事件處理程式是乙個帶有特定輸入引數的 如下所示 public delegate void myeventhandler object sender,myeventargs e 上面定義中的第乙個引數 sender 指定了發生事件的物件,第二個引數 e 儲存著在事件處理程式中要用到的資料。my...