委託

请明月發表於2024-10-18

基礎概念

委託(Delegate)特別用於實現事件和回撥方法。所有的委託(Delegate)都派生自 System.Delegate 類。
C# 事件(Event)是一種成員,用於將特定的事件通知傳送給訂閱者。事件通常用於實現觀察者模式,它允許一個物件將狀態的變化通知其他物件,而不需要知道這些物件的細節。
事件可以搭配委託做到觸發和回撥

例項化委託的格式:

//delegate <return type> <delegate-name> <parameter list>
public delegate void printString(string s);
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

委託的多播

委託物件可使用 "+" 運算子進行合併。一個合併委託呼叫它所合併的兩個委託。只有相同型別的委託可被合併。"-" 運算子可用於從合併的委託中移除元件委託。

public delegate void printString(string s);
//WriteToScreen與WriteToFile是具體方法
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

printString ps +=ps1;
printString ps +=ps2;
ps("輸入string值");//此時ps就會同時執行ps1和ps2
將委託作為引數回撥也是運用的一個方面
public delegate void printString(string s);
//WriteToScreen是具體方法
printString ps1 = new printString(WriteToScreen);

public static void sendString(printString ps){
	ps("輸入一個string值");
}
sendString(ps1);//執行ps1中的方法

程式碼示例

以下示例完成了一個簡單的委託中心,因為這裡沒有使用Event(事件),所以這裡沒有設定回撥。
DelegateCenter.cs

using System;
using System.Collections.Generic;
using UnityEngine;

public class DelegateCenter
{
    #region 單例
    private static DelegateCenter _instance;
    public static DelegateCenter Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = new DelegateCenter();
            }
            return _instance;
        }
    }
    #endregion
    public  delegate void DelegateEvent();

    private Dictionary<string, DelegateEvent> _events = new Dictionary<string, DelegateEvent>();

    public void RigisterDelegateEvent(string delegateName, DelegateEvent de)
    {
        if (_events.ContainsKey(delegateName))
        {
            _events[delegateName] += de;
        }
        else
        {
            _events.Add(delegateName, de);
        }
        Debug.Log($"{delegateName}事件註冊成功!");
    }

    public void InvokeDelegateEvent(string delegateName)
    {
        if (_events.ContainsKey(delegateName))
        {
            _events[delegateName].Invoke();
        }
    }

    public void RemoveDelegateEvent(string delegateName, DelegateEvent de)
    {
        if (_events.ContainsKey(delegateName))
        {
            _events[delegateName] -= de;
            Debug.Log($"{delegateName}事件解除安裝成功!");

        }

    }

    public void RemoveAllDelegateEvent()
    {
        _events.Clear();
        Debug.Log($"所有事件解除安裝成功!");
    }

}

表現

這裡的表現是使用上面的委託中心,因為這裡掛載了MonoBehaviour所以使用了幾個它的生命週期函式,在按下ASD鍵時會觸發相應的事件,但掛載了這個指令碼的物件刪除時會清除註冊了的事件。

using System;
using UnityEngine;
public class delegateTest:MonoBehaviour
{
    private void Start()
    {
        DelegateCenter.Instance.RigisterDelegateEvent("GameStart", GameStart);
        DelegateCenter.Instance.RigisterDelegateEvent("ResourcesLoad", ResourcesLoad);
        DelegateCenter.Instance.RigisterDelegateEvent("XluaHotFix", XluaHotFix);
    }

    private void Update()
    {
        if (Input.GetKeyUp(KeyCode.A))
        {
            DelegateCenter.Instance.InvokeDelegateEvent("GameStart");
        }
        else if (Input.GetKeyUp(KeyCode.S))
        {
            DelegateCenter.Instance.InvokeDelegateEvent("ResourcesLoad");
        }
        else if (Input.GetKeyUp(KeyCode.D))
        {
            DelegateCenter.Instance.InvokeDelegateEvent("ResourcesLoad");
        }
    }
    public void GameStart()
    {
        Debug.Log("遊戲開始");
    }
    public void ResourcesLoad()
    {
        Debug.Log("讀取資源");
    }
    public void XluaHotFix()
    {
        Debug.Log("開始熱更新");
    }
    private void OnDestory()
    {
        DelegateCenter.Instance.RemoveDelegateEvent("GameStart", GameStart);
        DelegateCenter.Instance.RemoveDelegateEvent("ResourcesLoad", ResourcesLoad);
        DelegateCenter.Instance.RemoveDelegateEvent("XluaHotFix", XluaHotFix);
    }
}

輸出:

相關文章