委托

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);
    }
}

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

原文地址:http://www.cnblogs.com/wuzhongke/p/16861325.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性