事件的由來
我們繼續思考上面的程式:上面的三個方法都定義在programe類中,這樣做是為了理解的方便,實際應用中,通常都是 greetpeople 在乙個類中,chinesegreeting和 englishgreeting 在另外的類中。現在你已經對委託有了初步了解,是時候對上面的例子做個改進了。假設我們將greetingpeople()放在乙個叫 greetingmanager的類中,那麼新程式應該是這個樣子的:
以下為引用的內容:
view plain
copy to clipboard
print?
namespace delegate
}
class program
private static void chinesegreeting(string name)
static void main(string args)
}
}
namespace delegate } class program private static void chinesegreeting(string name) static void main(string args) } }
這個時候,如果要實現前面演示的輸出效果,main方法我想應該是這樣的:
以下為引用的內容:
view plain
copy to clipboard
print?
static void main(string args)
static void main(string args)
我們執行這段**,嗯,沒有任何問題。程式一如預料地那樣輸出了:
morning, jimmy zhang
早上好, 張子陽
以下為引用的內容:
view plain
copy to clipboard
print?
static void main(string args)
輸出:morning, jimmy zhang
早上好, jimmy zhang
到了這裡,我們不禁想到:物件導向設計,講究的是物件的封裝,既然可以宣告委託型別的變數(在上例中是delegate1),我們何不將這個變 量封裝到 greetmanager類中?在這個類的客戶端中使用不是更方便麼?於是,我們改寫greetmanager類,像這樣:
以下為引用的內容:
view plain
copy to clipboard
print?
public class greetingmanager
//在greetingmanager類的內部宣告delegate1變數
public greetingdelegate delegate1;
public void greetpeople(string name, greetingdelegate makegreeting)
}
public class greetingmanager }
現在,我們可以這樣使用這個委託變數:
以下為引用的內容:
view plain
copy to clipboard
print?
static void main(string args)
static void main(string args)
儘管這樣達到了我們要的效果,但是似乎並不美氣,光是第乙個方法註冊用「=」,第二個用「+=」就讓人覺得彆扭。此時,輪到event出場了,c# 中可以使用事件來專門完成這項工作,我們改寫greetingmanager類,它變成了這個樣子:
以下為引用的內容:
view plain
copy to clipboard
print?
public class greetingmanager
}
public class greetingmanager}
很容易注意到:makegreet 事件的宣告與之前委託變數delegate1的宣告唯一的區別是多了乙個event關鍵字。看到這裡,你差不多明白到:事件其實沒什麼不好理解的,宣告乙個事件不過類似於宣告乙個委託型別的變數而已。
我們想當然地改寫main方法:
以下為引用的內容:
view plain
copy to clipboard
print?
static void main(string args)
greetingmanager gm = new greetingmanager();
gm.makegreet = englishgreeting;
// 編譯錯誤1
gm.makegreet += chinesegreeting;
gm.greetpeople("jimmy zhang", gm.makegreet);
//編譯錯誤2
}
static void main(string args)
這次,你會得到編譯錯誤:事件「delegate.greetingmanager.makegreet」只能出現在 += 或 -= 的左邊(從型別「delegate.greetingmanager」中使用時除外)。
事件和委託的編譯**
這時候,我們不得不注釋掉編譯錯誤的行,然後重新進行編譯,再借助reflactor來對 event的宣告語句做一**,看看為什麼會發生這樣的錯誤:
public event greetingdelegate makegreet;
可以看到,實際上儘管我們在greetingmanager裡將 makegreet 宣告為public,但是,實際上makegreet會被編譯成 私有字段,難怪會發生上面的編譯錯誤了,因為它根本就不允許在greetingmanager類的外面以賦值的方式訪問。
我們進一步看下makegreet所產生的**:
以下為引用的內容:
view plain
copy to clipboard
print?
private greetingdelegate makegreet;
//對事件的宣告 實際是 宣告乙個私有的委託變數
[methodimpl(methodimploptions.synchronized)]
public void add_makegreet(greetingdelegate value)
[methodimpl(methodimploptions.synchronized)]
public void remove_makegreet(greetingdelegate value)
private greetingdelegate makegreet; //對事件的宣告 實際是 宣告乙個私有的委託變數[methodimpl(methodimploptions.synchronized)] public void add_makegreet(greetingdelegate value)[methodimpl(methodimploptions.synchronized)]public void remove_makegreet(greetingdelegate value)
現在已經很明確了:makegreet 事件確實是乙個greetingdelegate型別的委託,只不過不管是不是宣告為public,它總是被宣告為private。另外,它還有兩個方 法,分別是add_makegreet和remove_makegreet,這兩個方法分別用於註冊委託型別的方法和取消註冊,實際上也就是: 「+= 」對應 add_makegreet,「-=」對應remove_makegreet。而這兩個方法的訪問限制取決於宣告事件時的訪問限制符。
在add_makegreet()方法內部,實際上呼叫了system.delegate的combine()靜態方法,這個方法用於將當前的變數新增到委託鍊錶中。我們前面提到過兩次,說委託實際上是乙個類,在我們定義委託的時候:
public delegate void greetingdelegate(string name);
當編譯器遇到這段**的時候,會生成下面這樣乙個完整的類:
以下為引用的內容:
view plain
copy to clipboard
print?
public class greetingdelegate:system.multicastdelegate
關於這個類的更深入內容,可以參閱《clr via c#》等相關書籍,這裡就不再討論了。
C 中的委託和事件 三
1 匿名方法 到目前為止,要想使委託工作,方法必須已經存在 即委託是用方法的簽名定義的 但使用委託還有另外一種方式 即通過匿名方法。匿名方法是用作委託引數的乙個 塊。用匿名方法定義委託的語法與前面的定義並沒有什麼區別。但在例項化委託時,就有區別了。下面是乙個非常簡單的控制台應用程式,說明了如何使用匿...
C 中的委託和事件
委託類似於c 中的函式指標,c 中的委託申明如下 delegate void mydelegate 只要該委託執行的方法與委託申明的簽名一致,就能呼叫委託來執行該方法,例如在本例中,有個方法為 void method 那麼就可以如下呼叫 mydelegate delegate new mydeleg...
C 中的委託和事件
委託 和 事件在 net framework中的應用非常廣泛,然而,較好地理解委託和事件對很多接觸c 時間不長的人來說並不容易。它們就像是一道檻兒,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委託和事件就覺得心裡憋得慌,渾身不自在。本文中,我將通過兩個範例由淺入深地講述什麼是委託 為什麼...