今天來講一講《C#delegate、event、Action、EventHandler的使用和區別》
小故事講解這四位的前世今生
曾經.Net大佬只有一個Delegete(委託),別人想用委託的時候,必須得用delegate關鍵字來定義一個委託,就像這樣
//定義一個無返回值的,帶一個int參數的委託
public delegate void myDelegate(int num);
話說,委託生來是爲了將方法也作爲參數進行傳遞的。所以後來它學會了發佈者/訂閱者模式。比如:
public myDelegate m_delegate;
m_delegate += MyFun;
public void MyFun(int num)
{
Debug.Log("my func: " + num);
}
但是它有一個弊端,delegate可以使用“=”將所有已經訂閱的取消(也可以用+/-對訂閱合併和刪除,這是後話,不講),只保留=後新的訂閱,這給了犯罪分子可乘之機。
m_delegate = MyFun1; //MyFun訂閱被取消,只有MyFun1在訂閱中
public void MyFun1(int num)
{
Debug.Log("my func1: " + num);
}
所以,event應運而生
event是一種特殊的委託,它只能+=,-=,不能直接用=
public event myDelegate m_event;
m_event += MyFun;
m_event = MyFun; //錯誤,
通過下面的報錯信息可以看出,event在定義類中(發佈者)是可以直接=的,但是在其他類中(訂閱者)就只能+= -=了,也就是說發佈者發佈一個事件後,訂閱者針對他只能進行自身的訂閱和取消。
但是,在事件發佈和訂閱的過程中,定義事件的原型委託類型常常是一件重複性的工作。
所以,EventHandler應運而生
它的出生就是爲了避免這種重複性工作,並建議儘量使用該類型作爲事件的原型。
//這是它的定義
//@sender: 引發事件的對象
//@e: 傳遞的參數
public delegate void EventHandler(object sender, EventArgs e);
//使用
public event EventHandler m_event; //修改自定義委託類型爲EventHandler
這時候老大哥delegate說了,你event都有小弟了,我也要有,我每次自定義委託的時候也很麻煩的。
所以,Action應運而生
//Action是系統預定義的一種委託,無返回值,參數在<>中傳入
public Action<int> m_action;
//比較下delegate和Action的定義(個人理解)
public delegate void myDelegate(int num);
public Action<int> m_action;
//1,Action省略了void,因爲它本身就是無返回值
//2, Action的參數在<>中定義的,delegate就是傳統定義
//3,delegate要用關鍵字,然後自定義一個委託名字。而Action委託名字已定。不需要delegate關鍵字。
知道每個類型因何而來,也就知道了應用場景和區別了,接下來是如何使用了。
使用
public class Event1 : MonoBehaviour
{
//delegate
public delegate void myDelegate(int num);
public myDelegate m_delegate;
//event
public event myDelegate m_event;
//EventHandler
public event EventHandler m_EventHandle;
//Action
public Action<int> m_action;
void Start()
{
m_delegate += MyEventFun;
m_delegate(1);
m_delegate = (d) =>{Debug.Log("m_delegate : " + d);};
m_delegate(2);
m_event += MyEventFun;
m_event(3);
//發佈者中可直接=
m_event = (d) =>{Debug.Log("m_event : " + d);};
m_event(4);
m_EventHandle += MyEventFun;
m_EventHandle(5, new EventArgs());
m_EventHandle += (o, e) =>{ Debug.Log("m_EventHandle: " + Convert.ToInt32(o) + "\t " + e.ToString());};
m_EventHandle(6, new EventArgs());
m_action += MyEventFun;
m_action(7);
m_action = (d) =>{Debug.Log("m_action : " + d);};
m_action(8);
}
public void MyEventFun(int num)
{
Debug.Log("my func1: " + num);
}
public void MyEventFun(object sender, EventArgs e)
{
Debug.Log("my func2: " + Convert.ToInt32(sender) + "\t " + e.ToString());
}
}
輸出: