C 中的事件處理

2022-07-22 01:15:14 字數 3523 閱讀 1303

事件(event)是乙個非常重要的概念,我們的程式時刻都在觸發和接收著各種事件:滑鼠點選事件,鍵盤事件,以及處理作業系統的各種事件。所謂事件就是由某個物件發出的訊息。比如使用者按下了某個按鈕,某個檔案發生了改變,socket上有資料到達。觸發事件的物件稱作傳送者(sender),捕獲事件並且做出響應的物件稱作接收者(receiver),乙個事件可以存在多個接受者。

在非同步機制中,事件是執行緒之間進行通訊的乙個非常常用的方式。比如:使用者在介面上按下乙個按鈕,執行某項耗時的任務。程式此時啟動乙個執行緒來處理這個任務,使用者介面上顯示乙個進度條指示使用者任務執行的狀態。這個功能就可以使用事件來進行處理。可以將處理任務的類作為訊息的傳送者,任務開始時,發出「taskstart」事件,任務進行中的不同時刻發出「taskdoing」事件,並且攜帶引數說明任務進行的比例,任務結束的時候發出「taskdone」事件,在畫面中接收並且處理這些事件。這樣實現了功能,並且介面和後台執行任務的模組耦合程度也是最低的。

具體說c#語言,事件的實現依賴於「**」(delegate)的概念,先了解一下**。

**(delegate)

delegate是c#

中的一種型別,它實際上是乙個能夠持有對某個方法的引用的類。與其它的類不同,

delegate

類能夠擁有乙個簽名(

signature

),並且它只能持有與它的簽名相匹配的方法的引用。它所實現的功能與

c/c++

中的函式指標十分相似。它允許你傳遞乙個類

a的方法m給另乙個類b的物件,使得類b的物件能夠呼叫這個方法m。但與函式指標相比,delegate有許多函式指標不具備的優點。首先,函式指標只能指向靜態函式,而delegate既可以引用靜態函式,又可以引用非靜態成員函式。在引用非靜態成員函式時,delegate不但儲存了對此函式入口指標的引用,而且還儲存了呼叫此函式的類例項的引用。其次,與函式指標相比,delegate是物件導向、型別安全、可靠的受控(managed)物件。也就是說,runtime能夠保證delegate指向乙個有效的方法,你無須擔心delegate會指向無效位址或者越界位址。

實現乙個

delegate

是很簡單的,通過以下

3個步驟即可實現乙個

delegate:1.

宣告乙個

delegate

物件,它應當與你想要傳遞的方法具有相同的引數和返回值型別。

2.建立

delegate

物件,並將你想要傳遞的函式作為引數傳入。

3.在要實現非同步呼叫的地方,通過上一步建立的物件來呼叫方法。

下面是乙個簡單的例子:

public class

mydelegatetest

", name);

} public static void

main

() }

輸出結果是:

hello, sam1111

下面我們來看看事件是如何處理的:

事件(event)

c#中的事件處理實際上是一種具有特殊簽名的

delegate

,象下面這個樣子:

public delegate void

myeventhandler(

object

sender, myeventargs e);

其中的兩個引數,

sender

代表事件傳送者,

e是事件引數類。

myeventargs

類用來包含與事件相關的資料,所有的事件引數類都必須從

system.eventargs

類派生。當然,如果你的事件不含特別的引數,那麼可以直接用

system.eventargs

類作為引數。

結合delegate

的實現,我們可以將自定義事件的實現歸結為以下幾步:

1:定義

delegate

物件型別,它有兩個引數,第乙個引數是事件傳送者物件,第二個引數是事件引數類物件。

2:定義事件引數類,此類應當從

system.eventargs

類派生。如果事件不帶引數,這一步可以省略。

3:定義事件處理方法,它應當與

delegate

物件具有相同的引數和返回值型別。

4:用event

關鍵字定義事件物件,它同時也是乙個

delegate

物件。5:用

+=操作符新增事件到事件佇列中(

-=操作符能夠將事件從佇列中刪除)。

6:在需要觸發事件的地方用呼叫

delegate

的方式寫事件觸發方法。一般來說,此方法應為

protected

訪問限制,既不能以

public

方式呼叫,但可以被子類繼承。名字是

可以是oneventname

。7:在適當的地方呼叫事件觸發方法觸發事件。

下面是乙個例子,例子模仿容器和控制項的模式,由控制項觸發乙個事件,在容器中捕捉並且進行處理。

事件的觸發者:

//////

事件的觸發者

///

public

class control

public

void raisesomeevent()

}//事件的觸發者自己對事件進行處理,這個方法的引數必須和**中聲名的一致

private

void processsomeevent(object sender, eventargs e)

}事件的接收者:

//////

事件的接收和處理者

///

class container

public

static

void main()

//這是事件的接受者對事件的響應

private

void responsesomeevent(object sender, eventargs e)

}程式執行的結果如下:

please input 'a':a

hello

some event occur!

事件的應用

例如有下面的需求需要實現:程式主畫面中彈出乙個子視窗。此時主畫面仍然可以接收使用者的操作(子視窗是非模態的)。子視窗上進行某些操作,根據操作的結果要在主畫面上顯示不同的資料。我發現一些程式設計師這樣實現這個功能:

主畫面彈出子視窗後,將自己的指標交給子畫面,然後在子畫面中使用這個指標,呼叫主畫面提供的方法,改變主畫面上的資料顯示。這樣雖然可以達到目的,但是各個模組之間產生了很強的耦合。一般說來模組之間的呼叫應該是單方向的:模組a呼叫了模組b,模組b就不應該反向呼叫a,否則就破壞了程式的層次,加強了耦合程度,也使得功能的改變和追加變得很困難。

這時正確的做法應該是在子視窗的操作過程中發出各種事件,而由主視窗捕捉這些事件進行處理,各個模組專心的做自己的事情,不需要過問其他模組的事情。

參考文獻

sam111的blog:c#

中的delegate

和event

C 中的事件處理

萬物皆物件!物件與物件之間不僅僅是存在關係,更是具有千絲萬縷的聯絡。關於物件之間的關係,我們在 sql server 中已經討論過。本文要討論的是它們之間存在的聯絡,即 如何使得乙個物件發生變化時,另乙個物件也能隨之發生變化。這種 乙個物件的狀態改變導致其它物件狀態改變 的現象,我們稱之為事件。在檢...

C 中的事件和事件處理

c 中的事件,我覺得和mfc的訊息作用在某些方面是差不多的。這個專案中用到的需求是兩個類之間的資料互動,首先肯定是分為乙個觸發事件的類,乙個處理事件的類。1 首先需要在所有類的外部為事件定義乙個公共訪問型別的 該 為多重 所以 定義方法標識的返回為void型別。一般我們這麼定義 public voi...

C 中的事件處理程式

c 中的事件處理程式是乙個帶有特定輸入引數的 如下所示 public delegate void myeventhandler object sender,myeventargs e 上面定義中的第乙個引數 sender 指定了發生事件的物件,第二個引數 e 儲存著在事件處理程式中要用到的資料。my...