這篇文章介紹了什麼是事件,以及如何在C#中使用事件。事件是在生活中發生的事情,它涉及到事件的發佈者和事件的訂閱者,當事件發生時,發佈者會發佈消息,訂閱者會接收通知並做出相應的處理。在C#中,我們可以使用event關鍵字定義一個事件,然後訂閱和取消事件的方法與委托鏈的取消和鏈接相同。 ...
1.什麼是事件
在生活中,我們有許多的事件,比如:你的朋友結婚,你就會給他送去祝福,這就是事件之一
你朋友結婚就是事件源,你送祝福就是處理事件對應的行為
事件往往會涉及兩角色——事件的發佈者和事件的訂閱者,當某個事件發生之後,事件的發佈者會發佈消息,事件的訂閱者會接收事件發生的通知,並做出相應的處理
2.使用事件
2.1 定義事件
// event關鍵字 委托類型
public event EventHandler birthday
事件的定義結構為
訪問修飾符 event 委托類型 事件名稱
註意
:
- 修飾符一般定義為public,因為事件訂閱者需要對事件進行訂閱與取消操作,定義為公共類型可以使得事件對其他類可見
- 事件的委托類型,既可以是自定義的委托類型,還可以是.NET類庫中預定義的EventHanler
2.2 訂閱與取消事件
事件的訂閱和取消,和我們昨天說到的委托鏈的取消和鏈接相同,因為事件的處理其實就是調用委托包裝後的方法
public class Bridegroom {
// 1.自定義委托
public delegate void EventHandler(string msg);
// 2.自定義事件
public event EventHandler MarryEvent;
// 3.發出事件
public void OnMarringComing(string msg) {
// 4.判斷是否綁定了事件處理方法
if (MarryEvent != null) {
// 5.觸發事件
MarryEvent(msg);
}
}
public static void Main(string[] args) {
Bridegroom bridegroom = new Bridegroom();
Friend friend1 = new Friend("張三");
Friend friend2 = new Friend("李四");
Friend friend3 = new Friend("王五");
// 添加事件的訂閱者
/*
這裡是給MarryEvent這個事件,綁定委托鏈
委托鏈的增加和減少使用的就是 +、-
*/
bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);
bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);
// 發出事件
Console.WriteLine("===============================");
bridegroom.OnMarringComing("朋友們,我結婚了!");
bridegroom.OnMarringComing("朋友們,我結婚了!");
Console.Read();
}
}
public class Friend {
private string name;
public string Name { get { return this.name; } set { this.name = value; } }
public Friend(string name)
{
this.name = name;
}
public void sendMessage(string message) {
Console.WriteLine(message);
Console.WriteLine(this.Name+"收到了消息");
}
}
除了可以使用自定義委托的方式,來定義事件外,還可以使用.NET類庫中的預定義的委托類型 EventHandler 來定義事件
public class Bridegroom
{
// 2.自定義事件
public event EventHandler MarryEvent;
// 3.發出事件
public void OnMarringComing(string msg)
{
// 4.判斷是否綁定了事件處理方法
if (MarryEvent != null)
{
Console.WriteLine(msg);
// 5.觸發事件
MarryEvent(msg,new EventArgs());
}
}
public static void Main(string[] args)
{
Bridegroom bridegroom = new Bridegroom();
Friend friend1 = new Friend("張三");
Friend friend2 = new Friend("李四");
Friend friend3 = new Friend("王五");
// 添加事件的訂閱者
/*
這裡是給MarryEvent這個事件,綁定委托鏈
委托鏈的增加和減少使用的就是 +、-
*/
bridegroom.MarryEvent += new EventHandler(friend1.sendMessage);
bridegroom.MarryEvent += new EventHandler(friend2.sendMessage);
// 發出事件
bridegroom.OnMarringComing("朋友們,我結婚了!");
Console.WriteLine("===============================");
Console.Read();
}
}
public class Friend
{
private string name;
public string Name { get { return this.name; } set { this.name = value; } }
public Friend(string name)
{
this.name = name;
}
public void sendMessage(object obj,EventArgs args)
{
Console.WriteLine(this.Name + "收到了消息");
}
}
EventHandler 是 .NET 類庫中的預定義的委托類型,用於處理不含事件數據的事件,如果想在事件中包含事件數據,可以通過派生(繼承)EventArgs來實現
從EventHandler委托的定義可以看出:
- 委托的返回類型為void,因此實例化委托類型的方法也需要滿足這一點
- 第一個參數 sender 負責保存對觸發事件的對象引用,其類型為object
- 第二個參數 e 負責保存事件的數據,EventArgs 類也是 .NET 類庫中定義的類,它不保存任何數據
2.3 擴展EventArgs類
public class MarryArgs : EventArgs {
public string Message;
public MarryArgs(string message)
{
this.Message = message;
}
}
public class Bridegroom
{
public delegate void MarryEventHandler(object obj, MarryArgs e);
// 2.自定義事件
public event MarryEventHandler MarryEvent;
// 3.發出事件
public void OnMarringComing(string msg)
{
// 4.判斷是否綁定了事件處理方法
if (MarryEvent != null)
{
// 5.觸發事件
MarryEvent(this,new MarryArgs(msg));
}
}
public static void Main(string[] args)
{
Bridegroom bridegroom = new Bridegroom();
Friend friend1 = new Friend("張三");
Friend friend2 = new Friend("李四");
Friend friend3 = new Friend("王五");
// 添加事件的訂閱者
/*
這裡是給MarryEvent這個事件,綁定委托鏈
委托鏈的增加和減少使用的就是 +、-
*/
bridegroom.MarryEvent += new MarryEventHandler(friend1.sendMessage);
bridegroom.MarryEvent += new MarryEventHandler(friend2.sendMessage);
// 發出事件
bridegroom.OnMarringComing("朋友們,我結婚了!");
Console.WriteLine("===============================");
bridegroom.MarryEvent -= new MarryEventHandler(friend2.sendMessage);
bridegroom.MarryEvent += new MarryEventHandler(friend3.sendMessage);
bridegroom.OnMarringComing("朋友們,我結婚了!");
Console.Read();
}
}
public class Friend
{
private string name;
public string Name { get { return this.name; } set { this.name = value; } }
public Friend(string name)
{
this.name = name;
}
public void sendMessage(object obj,MarryArgs args)
{
Console.WriteLine(args.Message);
Console.WriteLine(this.Name + "收到了消息");
}
}
我們可以通過派生的方式,讓EventArgs攜帶事件數據
事件的本質
從事件的執行過程,我們可以看出,事件定義中包含委托,事件和委托到底有什麼關係呢?
public class Program {
public delegate void MarryHandler(string msg);
public event MarryHandler OnMarry;
static void Main(string[] args) {
Console.WriteLine("Line");
}
}
從IL代碼中,我們可以看出,MarryHandler委托被編譯成一個名為MarryHandler的類,而OnMarry事件則被編譯上圖的代碼
我們查看add_OnMarry方法,我們發現它其實是調用了 Delegate.Combine()
這個方法,Delegate.Combine() 這個方法是將多個委托組合成為了一個多路廣播委托
而remove_OnMarry()方法,則是調用了 Delegate.Remove()
這個方法,Delegate.Remove() 這個方法是將委托從多路廣播委托中刪除
而我們還有個OnMarry的欄位定義
我們發現OnMarry欄位主要是有一個私有的欄位類型為MarryHandler的委托類型
總結:事件的本質,其實就是 C# 中的一個特殊的多路廣播委托(我們把鏈接多個方法的委托稱之為多路廣播委托),事件預設含有一個委托類型的變數,該變數用於保存對事件處理方法的引用,且該委托類型的變數為私有,只能從定義該時間的類中進行訪問