delegate 委托

委托

delegate关键词

event关键字,添加后将委托封装成事件。

事件和委托区别:事件相对于委托来说更加安全。

四种类型委托

// 自定义无参无返回值
public delegate void ActionX();
// 自定义有参无返回值
public delegate void ActionY(int a);
// 自定义有参无返回值
public delegate void ActionZ<T>(T a);
// 自定义有参有返回值
public delegate int ActionU(int a,int b);

class Teacher {
    // (自定义无参无返回值委托)
    public ActionX action1;
    // (自定义有参无返回值委托)
    public ActionY action2;
    // (自定义有参无返回值委托)
    public ActionZ<string> action3;
    // (自定义有参有返回值委托)
    public ActionU action4;
    // 将委托封装成事件
    public event ActionX action5;
     
    // (系统自带无参无返回值委托)
    public Action action6;
    // (系统自带有参无返回值委托)
    public Action<int> action7;
    // (系统自带有参有返回值委托)
    // 前面的是参数,最后一个是返回值
    public Func<int, int, int> action8;

    public void Test(int a,int b) {
        action1?.Invoke();
        action2?.Invoke(a);
        action3?.Invoke(a.ToString());
        action4?.Invoke(a, b);

        action6?.Invoke();
        action7?.Invoke(a);
        action8?.Invoke(a, b);
    }
}

class Teacher2 {
    public Teacher2(Teacher teacher) {
        teacher.action1 += Test;
        teacher.action1 = Test;

        teacher.action5 += Test;
        // 将委托封装成事件后,外部调用只能通过 += 和 -= 进行调用不能够使用 = 但在内部可以使用
        //teacher.action5 = Test;
    }

    private void Test() {
        
    }
}

自定义委托类型

public delegate void Lecture();
    class Teacher {
    public Lecture lecture;
    public Teacher() {
        /*注册委托的四种方式,其中方法二和方法四较为常用,剩下两种尽量掌握,防止遇见不认识*/
        // 注册委托方法一
        lecture += new Lecture(action1);
        // 注册委托方法二
        lecture += action2;
        // 注册委托方法三
        lecture += delegate () { Console.WriteLine("我是注册的第三种委托,不常用"); };
        // 注册委托方法四
        lecture += () => { Console.WriteLine("我是注册的第四种委托,常用"); };

        /*委托单播和多播*/

        // 委托多播,委托方法执行,像委托中注册的多个函数都会执行,就称为多播。
        lecture += action1;
        lecture += action2;

        // 委托单播,委托方法执行,只会执行最后等号的函数,称为单播,但若是在后面再添加其他函数后添加的函数也是会执行的
        lecture = action1;

        // 委托事件删除,和数组删除单个元素类似
        lecture -= action1;

        // 委托事件清空,和清空数组类似
        lecture = null;
    }

    private void action1() {
        Console.WriteLine("我是注册的第一种委托,不常见");
    }

    private void action2() {
        Console.WriteLine("我是注册的第二种委托,常见");
    }
}

案例一:利用委托实现玩家扣血,UI刷新功能

玩家血量逻辑

/*玩家的数据,通过向外部暴露一个委托,从而减少代码之间的耦合度*/
using UnityEngine;

// 声明一个血量变动的委托
public delegate void HpChange(float curHp, float maxHp);

public class Player : MonoBehaviour
{
    // 将声明的委托进行实例化
    public HpChange Hurt;
    // 当前血量
    float curHp;
    // 最大血量
    float maxHp;
     
    void Start() {
        // 初始化赋值
        curHp = maxHp = 100;
        // 首次执行,刷新委托,防止显示不正确
        Hurt?.Invoke(CurHp,maxHp);
    }

    public float CurHp {
        get => curHp;
        set {
            // 血量变动
            curHp = value;
            // 执行委托方法
            Hurt?.Invoke(CurHp,maxHp);
        }
    }

    // 测试逻辑
    [ContextMenu("扣血")]
    public void HurtTest() {
        CurHp -= 10;
    }
}

UI显示逻辑

/*显示UI脚本,通过向玩家的委托中注册事件,无需获得玩家的对应数据也可以获得相应的显示效果*/
using UnityEngine;
using UnityEngine.UI;

// 玩家血量UI
public class PlayerHpUI : MonoBehaviour
{
    // 玩家
    Player player;
    // 血量Image
    Image imageHp;
    // 血量Text
    Text textHp;

    void Awake() {
        // 获得要显示的UI
        imageHp = GameObject.Find("HpImage").GetComponent<Image>();
        textHp = GameObject.Find("HpImage/Hp").GetComponent<Text>();
        // 获得对应的游戏物体
        player = FindObjectOfType<Player>();
        // 向游戏物体中的委托注册血量变动的方法
        player.Hurt += hpShow;
    }

    //血量显示,当游戏物体上的委托调用,这里也会相应的调用
    private void hpShow(float curHp, float maxHp) {
        imageHp.fillAmount = curHp / maxHp;
        textHp.text = curHp + "/" + maxHp;
    }    
}

案例二:做家务

using System;

namespace BigTalk {
    class Program {
        static void Main(string[] args) {
            Mom mom = new Mom();
            Dad dad = new Dad(mom);
            My my = new My(mom);
            mom.StartKeepHouse();
        }
    }

    // 声明一个做家务的委托
    public delegate void KeepHouse();

    class Mom {
        public KeepHouse KeepHouse;

        public Mom() {
            KeepHouse += washSheets;
        }

        private void washSheets() {
            Console.WriteLine("我今天的家务活就是洗床单");
        }

        // 开始做家务
        public void StartKeepHouse() {
            KeepHouse?.Invoke();
        }
    }

    class Dad {
        public Dad(Mom mom) {
            mom.KeepHouse += mopTheFloor;
        }

        private void mopTheFloor() {
            Console.WriteLine("我今天的家务活就是拖地板");
        }
    }

    class My {
        public My(Mom mom) {
            mom.KeepHouse += residue;
        }

        private void residue() {
            Console.WriteLine("剩余的家务活都是我的");
        }
    }
}

委托的其他用法

class Program {
    static void Main(string[] args) {
        Teacher teacher = new Teacher();
        teacher.Calculate(4,5,add);
    }

    private  static void add(int arg1, int arg2) {
        Console.WriteLine(arg1 + arg2);
    }
}

class Teacher {
    public void Calculate(int a, int b, Action<int, int> callback) {
        callback?.Invoke(a, b);
    }
}

系统自带的委托都可以通过自定义委托进行实现
开发时减少彼此代码之间的耦合度

posted @ 2022-11-05 21:10  坞中客  阅读(19)  评论(0编辑  收藏  举报