2010-08-23 87 views
6

我需要一些幫助,瞭解如何創建新的自定義事件。我從here讀...C#:瞭解事件語法

public delegate void ChangingHandler (object sender, CarArgs ca); 
public event ChangingHandler Change; 
... 
private void car_Change(object sender, CarArgs ca) { 
    MessageBox.Show(ca.Message()); 
} 
... 
car.Change+=new Car.ChangingHandler(car_Change); // add event handler 
... 
Change(this,ca); // call event 

月1日,我真的不得到代表的一部分。在一個正常的變量declartion,

protected string str1; 

但在這裏我有多餘的(ChangingHandler)。我如何理解這一點?我知道像ChangingHandler這樣的東西會被用來處理事件,但它會把我拋棄。

public event ChangingHandler Change 

然後

car.Change+=new Car.ChangingHandler(car_Change) 

我真的不得到語法new Car.ChangingHandler(car_Change)

回答

17

C#中的事件有點像方法指針的集合。它說:「嘿大家,如果你關心我,給我一個指向我可以調用的方法的指針,我會堅持下去,當我覺得向世界宣佈什麼時候到來,我會調用所有的方法你給我。」

這樣,有人可以給事件一個指向他們的方法的指針,它被稱爲「事件處理程序」。只要事件的主人認爲合適,該事件就會調用此方法。

從這個意義上講,代表只不過是說事件會接受什麼樣的方法。你不能讓一個人給這個事件提供一個沒有參數的方法,一個需要5個參數的方法,它不知道如何調用它們。所以委託是事件和事件處理程序之間的契約,告訴他們對方法簽名的期望。

在你的情況下,它可能是更好的只是使用EventHandler<T>,這是一座建於形式void EventHandler<T>(object sender, T eventArgs)的委託爲您的活動委託,像這樣:

public event EventHandler<CarArgs> Change; 

C#實際上並沒有函數指針在原始意義上。代表處理這個。它們就像強類型的,面向對象的函數指針。當你調用

car.Change+=new Car.ChangingHandler(car_Change); 

你給指向您car_Change事件處理程序,告知事件打電話給你car_Change方法時,它已準備就緒的情況下一個新的委託(函數指針)。委託(new ChangeHandler(...)只是封裝的指針car_Change方法。

+1

請注意,您不需要顯式創建委託實例。你可以做'car.Change + = car_Change;'(這非常習慣) – bruceboughton 2010-08-23 15:00:11

3

而且事實證明你不需要car.Change += new Car.ChangingHandler(car_Change);作爲語法時才它並不像你指出的非常直觀。

你可以簡單地寫car.Change += car_Change;假設car_Change有正確的方法簽名。

11

事件具有一定的簽名。這個簽名定義了一個偵聽必須看起來像在什麼參數,它應該有什麼樣的返回類型。本合同是通過定義一個表達方面代表。從您的代碼示例:

public delegate void ChangingHandler (object sender, CarArgs ca); 

這裏我們定義了一個委託服用objectCarArgs作爲參數,並用void返回類型的方法。

接下來,聲明事件本身:

public event ChangingHandler Change; 

所以,我們有一個叫做Change一個事件,事件的監聽器必須具有相同的簽名ChangingHandler委託。

然後,我們需要一個監聽方法:

private void car_Change(object sender, CarArgs ca) { 
    MessageBox.Show(ca.Message()); 
} 

在這裏,我們可以看到它具有相同的簽名ChangingHandler委託。

最後,我們可以讀心人連接到事件:

car.Change+=new Car.ChangingHandler(car_Change) 

所以,我們創建一個新的ChangingHandler實例指car_Change方法,並委託實例傳遞給事件。

所有這一切說,我會建議使用,而不是創建自己的預定義EventHandler<T>代表:

public event EventHandler<CarArgs> Change; 
0

一個思考它的粗暴的方式:委託類型定義了將要「的功能形狀」成爲你的事件的基礎。所以ChangingHandler是函數的樣子。進一步說,委託實例就像一個函數指針。用這些術語來思考它。

public event ChangingHandler Change定義了一個叫做Change的函數指針,它將指向形狀爲ChangingHandler的函數。

但是目前這個函數指針沒有指向任何東西。這就是car.Change += new Car.ChangingHandler(car_Change)比特進來的地方。

分兩步進行。代表不是正常的函數指針;它們實際上更像是函數指針堆棧,可以將多個函數傳遞給委託。這就是爲什麼你聽到人們更普遍地談論「訂閱」一個事件;將事件添加到事件中意味着事件觸發時會調用它。使用+ =運算符將函數添加到代理「堆棧」。

你不能直接將一個函數直接添加到委託,它已經用委託本身表達。這是以一次性方式完成的,在你將函數添加到事件的同一行上創建一個new對象;儘管自C#2.0以來我相信你可以直接添加函數而不用調用new語法。

1

事件是基於委託的概念,委託基本上是一個方法簽名的定義。就這樣。就像在一個界面中你如何定義方法簽名一樣,但是你沒有實現它們,你可以在所有繼承該接口的類中這樣做。

委託是一個方法簽名的定義,以及您可以定義爲許多方法身體是你喜歡的,例如,鑑於這一委託(方法簽名的定義):

public delegate void ChangingHandler (object sender, CarArgs ca); 

您可以定義與此委託(方法簽名的定義),因爲這些機構:

public void SomeMethodWhichCreatesADelegateBody() 
{ 
    ChangingHandler myChangingHandler = new ChangingHandler(
     delegate(object sender, EventArgs e) { /* the method body for myChangingHandler */ } 
    ); 
} 

這雖然定義爲代表的老風格,現在它更具可讀性,而不是使用委託關鍵字的lambda表達式像我一樣創建方法體,但這對於這些並不重要 問題。

現在可以將事件想象成一個委託(方法簽名定義),其中包含一個body數組,用於訂閱事件,訂閱方法體的語法爲+=,還有用於從事件的訂閱是-=

所以這裏這個代碼定義身體爲ChangingHandler委託陣列(方法簽名的定義)去除的方法體:

public event ChangingHandler Change; 

而且你可以訂閱身體的(它們添加到數組)通過calli進行分組NG的方法:

public void SomeMethodWhichSubscribesADelegateBodyToAnEvent() 
{ 
    ChangingHandler myChangingHandler = new ChangingHandler(
     delegate(object sender, EventArgs e) { /* the method body for myChangingHandler */ } 
    ); 

    Change += myChangingHandler; 
} 

現在的全部理由進行這項活動,有法人體的,只要你想,你去定義和添加的數組,就是這樣,每當一個事件發生在物體內部誰擁有該事件,該對象可以執行所有這些方法,以便在該事件發生時執行您想要完成的任何操作。擁有該對象的對象的確如此:

if (Change != null) // You wouldn't access an array without making sure it wasn't null, would you? 
{ 
    Change(this, new CarArgs()); // This executes every method body in it's array using the signature definition the delegate defined. 
    // The delegate simply exists so this code knows the method signature 
    // so it can know how to call those method body's for you. 
}