相信不少初學者對于委托和事件理解的不夠深刻。一直有個疑惑:它們的區(qū)別在哪户誓?什么時候該使用它們取具?本篇文章就幫助你快速理解這對雙胞胎兄弟价认。
委托是就像類一樣,它是一種用戶自定義的數(shù)據(jù)類型顾患。有了類型番捂,必然就有實例(對象),每個委托實例都可以關(guān)聯(lián)多個方法江解,且這些方法必須與委托的類型和返回值相同设预。
而事件本身就是一個對象,它就是狹義的委托犁河,每個事件可用"="關(guān)聯(lián)一個方法,或用"+="關(guān)聯(lián)多個方法鳖枕。
因此魄梯,委托和事件本質(zhì)區(qū)別就是類型和對象的區(qū)別。那么宾符,什么時候使用委托画恰,什么時候用事件呢?簡單來說吸奴,當有多個同類型同返回值的方法等著在特定情況下一起被觸發(fā)允扇,建議使用用委托來管理它們;除此之外,使用事件會更加便捷则奥。
委托使用舉例:
public class Reality
{
? ? //聲明一個委托類型
? ? public delegate void DoSomething(string s);
? ? //創(chuàng)建一個委托實例
? ? public DoSomething doSomething;
? ? //創(chuàng)建委托實例并賦值(關(guān)聯(lián)一個靜態(tài)的考润、與委托同類型和返回值的方法)
? ? DoSomething toDo = new DoSomething(To_do);
? ? DoSomething toStop = new DoSomething(To_stop);
? ?//構(gòu)造方法
? ? public Reality()
? ? {
? ? ? ? //將兩個委托實例合并給另一個委托實例doSomething
? ? ? ? doSomething = toDo;
? ? ? ? doSomething += toStop;
? ? }
? ? private static void To_do(string s)
? ? {
? ? ? ? Debug.Log("he ready to "+s);
? ? }
? ? private static void To_stop(string s)
? ? {
? ? ? ? Debug.Log("he stop to " + s);
? ? }
}
//調(diào)用委托
public class test : MonoBehaviour
{
? ? Reality reality = new Reality();
? ? private void Start()
? ? {
? ? ? ? //使用委托實例,相當于調(diào)用它關(guān)聯(lián)的所有方法
? ? ? ? reality.doSomething("eat");
? ? }
}
說完委托读处,這里再介紹三種經(jīng)常用到的事件:
1.Action系列的泛型事件糊治。它是沒有返回值的事件,最多可以有16參數(shù)罚舱,也可以沒有參數(shù)
示例:
?*聲明事件(可以傳入數(shù)據(jù)類型)?
? ? ? ? public event Action<Transform,Vector3> Drag;? ?
*注冊事件井辜,關(guān)聯(lián)方法
? ? ? ?Drag += new Action<Transform,Vector3>(fun);? ? ? //使用+=或=」苊疲‘+=’能綁定多個方法粥脚,‘=’則指定為一個。
? ? ? ?public void fun(Transform a,Vector3?b) { }? ? ?//方法示例
*調(diào)用事件
? ? ? Drag?.Invoke(transform,Vector3.up);? ? ?//有參數(shù)的事件包个,需要傳參數(shù)
2.Func系列的事件刷允。它具有返回值,最多可以有16個參數(shù)碧囊;它封裝一個具有參數(shù)(也許沒有)但卻返回 TResult 參數(shù)指定的類型值的方法树灶。
示例1:
//聲明事件。最后一個"string"是返回類型,前面兩個都是傳入的參數(shù)類型糯而。
public static Func<int, float, string> func;? ??
//注冊事件
func = new Func<int,float,string>(fun);? ? ??
?//調(diào)用事件??
?string s = func(1,0.5f);? ?
?//目標方法
string fun(int a,float b)? {?return (a + b).ToString(); }? ? ? ? ?
示例2 (在Unity協(xié)程中的運用):
bool IsHit { return false; }? ? ?//返回布爾值的方法
IEnumerator Test()? ?{
? ? ? ? Func<bool> A = IsHit;? ? ? //定義事件A(返回bool值的事件)天通,關(guān)聯(lián)IsHit方法
? ? ? ? Debug.Log("等待A為True。熄驼。像寒。");
? ? ? ? yield return new WaitUntil(A);? ? //等待A為true時繼續(xù)往下執(zhí)行。
}
3.Unity內(nèi)置的事件
上述兩種事件類型都是屬于System名稱空間下谜洽,這里再介紹一個屬于UnityEngine.Events名稱空間下的兩兄弟:UnityAction和UnityEvent萝映。
UnityAction是Unity內(nèi)部實現(xiàn)的事件傳遞系統(tǒng)(屬于函數(shù)指針,將方法傳遞到別的類中執(zhí)行)阐虚,而UnityEvent負責管理UnityAction,它提供了AddListener,RemoveListener等方法蚌卤;UnityAction只可調(diào)用自己实束,而UnityEvent可同時調(diào)用多個UnityAction奥秆。此外,在檢視面板中咸灿,還可以對UnityEvent進行賦值操作构订。
示例:
//聲明實例
? ? public UnityAction<int, string> a1;
? ? public UnityAction<int, string> a2;
? ? public UnityEvent<int, string> myEvents;
//目標方法
? ? public void fun1(int a, string b) { }
? ? public void fun2(int a, string b) { }
//使用"="或"+="關(guān)聯(lián)方法
? ? ? ? a1 = fun1;
? ? ? ? a2 = fun2;
//向UnityEvent實例中添加UnityAction實例
? ? ? ? myEvents.AddListener(a1);
? ? ? ? myEvents.AddListener(a2);
//如果需要移除某個事件,則使用RemoveListener
? ? ? ? myEvents.RemoveListener(a1);
//全部移除
? ? ? ? myEvents.RemoveAllListeners();
?//調(diào)用事件
? ? ? ? a1(1,"a");? ? ?//通過UnityAction直接調(diào)用
? ? ? ? a2(2, "b");
? ? ? ? myEvents.Invoke(3,"c");? ? ?//通過UnityEvent統(tǒng)一調(diào)用
OK,關(guān)于委托和事件的介紹就到此結(jié)束了避矢,各位小伙伴是不是理解更深刻了呢悼瘾?