Unity 自定义委托以及事件解读

本文详细介绍了Unity中委托和事件的概念及使用方法。委托是引用类型,用于封装一个或多个方法,允许调用与之兼容的方法。事件是委托的封装,用于类间通信,遵循添加、移除事件处理器的规则。文章通过实例展示了如何声明、分发、执行和销毁委托,以及如何声明和调用事件。此外,还解释了委托和事件之间的关系及其在事件处理中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Unity 自定义委托以及事件解读

如果有说的不对的地方欢迎指正。
资料参考:小Joe的学习课堂 哈哈哈.

什么是委托

    委托:引用类型的数据类型
    关键字:delegate
    定义:委托可以封装一个或者多个方法
    委托类型的实例可以和任何其他方法相关联起来,只要类型兼容 
    换句话说就是只要返回值和签名相同就可以通过委托实例来间接调用这些方法

如何声明一个委托

    //委托声明 
    // public 公开程度 delegate 关键字    void  目标方法的返回值  参数  空
    //_Delegate  可匹配方法(类型兼容):参数以及返回值为空的方法
    
    //无参
   public delegate void _Delegate();
    //带参
    public delegate string _DelegateStr(string _PrintStr);

自定义委托变量声明以及Unity 封装委托变量声明

    //自定义委托变量
    private _Delegate _MyDelegate;
    private _DelegateStr _MyDelegateStr;

    // Action 委托定义: 可兼容无返回值有参方法  无法兼容有返回值方法
    private Action _MyAction;
    private Action<string> _MyActionStr;

    // Func 委托定义: 可兼容有返回值有参方法  无法兼容无返回值方法
    //书写格式  < 参数类型 , 返回值类型 >
    private Func<int, string> _MyFunc;
    private Func<string> _MyFuncStr;

委托消息分发

注意一点如果自定义委托是用 “=”操作符是会覆盖当前所属同属性广播的。
举个例子:A+=A ; Pint(A); 会输出不同值,但是 A=A ; Pint(A);会输出单一值。
可能有那一点不是很形象,但也差不太多【尴尬】其实自己试一下就知道我说的什么意思了。

       //消息分发
        //委托可使用单路广播的形式
        _MyDelegate = new _Delegate(DebugLog);
        _MyDelegateStr = new _DelegateStr(DebugLogStr);

        _MyAction = new Action(DebugLog);
        _MyActionStr = new Action<string>(DebugLogStrNot);

        _MyFunc = new Func<int, string>(DebugLogStrInt);
        _MyFuncStr = new Func<string>(DebugLogStrOut);


        //也可使用多路广播的形式
        //执行的顺序也还是添加方法的顺序
        _MyDelegate += DebugLog;
        _MyDelegate += DebugLog02;
        _MyDelegate += DebugLog03;

        _MyAction += DebugLog;
        _MyAction += DebugLog02;
        _MyAction += DebugLog03;

委托执行

       //执行
        //不带参数
        _MyDelegate();
        _MyAction();
        _MyFuncStr();

        //带参数
        _MyDelegateStr("_MyDelegateStr");

        _MyActionStr("_MyActionStr");

        _MyFunc(12);

委托销毁

    /// <summary>
    /// 当前脚本 关闭的时候 注销委托方法 繁殖内存泄漏
    /// </summary>
    private void OnDestroy()
    {
        //注销委托方法
        _MyDelegate -= new _Delegate(DebugLog);
        _MyDelegate -= new _Delegate(DebugLog02);
        _MyDelegate -= new _Delegate(DebugLog03);
        
        _MyAction -= DebugLog;
        _MyAction -= DebugLog02;
        _MyAction -= DebugLog03;
    }

自定义委托代码

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

/// <summary>
/// 自定义委托
/// </summary>

public class CustomDelegate_ZH : MonoBehaviour
{
    //委托关键字:delegate
    //委托:引用类型的数据类型
    //定义:委托可以封装一个或者多个方法
    //委托类型的实例可以和任何其他方法相关联起来,只要类型兼容 换句话说就是只要返回值和签名相同就可以通过委托实例来间接调用这些方法

    //委托声明
    // public 公开程度 delegate 关键字    void  目标方法的返回值  参数  空
    //_Delegate  可匹配方法(类型兼容):参数以及返回值为空的方法
    public delegate void _Delegate();
    //带参
    public delegate string _DelegateStr(string _PrintStr);

    //自定义委托变量
    private _Delegate _MyDelegate;
    private _DelegateStr _MyDelegateStr;

    // Action 委托定义: 可兼容无返回值有参方法  无法兼容有返回值方法
    private Action _MyAction;
    private Action<string> _MyActionStr;

    // Func 委托定义: 可兼容有返回值有参方法  无法兼容无返回值方法
    //书写格式  < 参数类型 , 返回值类型 >
    private Func<int, string> _MyFunc;
    private Func<string> _MyFuncStr;




    /// <summary>
    /// 当前对象激活时执行
    /// </summary>
    private void OnEnable()
    {
        //消息分发
        //委托可使用单路广播的形式
        _MyDelegate = new _Delegate(DebugLog);
        _MyDelegateStr = new _DelegateStr(DebugLogStr);

        _MyAction = new Action(DebugLog);
        _MyActionStr = new Action<string>(DebugLogStrNot);

        _MyFunc = new Func<int, string>(DebugLogStrInt);
        _MyFuncStr = new Func<string>(DebugLogStrOut);


        //也可使用多路广播的形式
        //执行的顺序也还是添加方法的顺序
        _MyDelegate += DebugLog;
        _MyDelegate += DebugLog02;
        _MyDelegate += DebugLog03;

        _MyAction += DebugLog;
        _MyAction += DebugLog02;
        _MyAction += DebugLog03;



        #region //委托执行

        //执行
        //不带参数
        _MyDelegate();
        _MyAction();
        _MyFuncStr();

        //带参数
        _MyDelegateStr("_MyDelegateStr");

        _MyActionStr("_MyActionStr");

        _MyFunc(12);

        #endregion


    }

    /// <summary>
    /// 当前脚本 关闭的时候 注销委托方法 繁殖内存泄漏
    /// </summary>
    private void OnDestroy()
    {
        //注销委托方法
        _MyDelegate -= new _Delegate(DebugLog);
        _MyDelegate -= new _Delegate(DebugLog02);
        _MyDelegate -= new _Delegate(DebugLog03);

        _MyAction -= DebugLog;
        _MyAction -= DebugLog02;
        _MyAction -= DebugLog03;
    }

    /// <summary>
    /// 委托匹配方法
    /// 说明:无返回值、无参数
    /// </summary>
    public void DebugLog()
    {
        Debug.Log("无参无返回值 委托调用成功:DebugLog");
    }

    /// <summary>
    /// 无返回值无参 方法
    /// </summary>
    private void DebugLog02()
    {
        Debug.Log("无参无返回值 委托调用成功:DebugLog02");
    }

    /// <summary>
    /// 无返回值无参 方法
    /// </summary>
    private void DebugLog03()
    {
        Debug.Log("无参无返回值委托调用成功:DebugLog03");
    }

    /// <summary>
    /// 无返回值有参 方法
    /// </summary>
    /// <param 参数="_Str"></param>
    private void DebugLogStrNot(string _Str)
    {
        _Str = _Str + ":无返回值有参 委托调用成功:DebugLogStrNot";

        Debug.Log(_Str);
    }

    /// <summary>
    /// 有返回值无参 方法
    /// </summary>
    /// <param 参数="_Str"></param>
    private string DebugLogStrOut()
    {
        string _Str = "";
        _Str = _Str + ":有返回值无参 委托调用成功:DebugLogStrOut";
        Debug.Log(_Str);
        return _Str;
    }

    /// <summary>
    /// 有返回值 有参 方法
    /// </summary>
    /// <param 参数="_Str"></param>
    /// <returns></returns>
    private string DebugLogStr(string _Str)
    {
        _Str = _Str + ":有参有返回值 委托调用成功:DebugLogStr";

        Debug.Log(_Str);

        return _Str;
    }


    /// <summary>
    /// 有返回值 有参 方法
    /// </summary>
    /// <param 参数="_Int"></param>
    /// <returns></returns>
    private string DebugLogStrInt(int  _Int)
    {
        string _Str;
        _Str = _Int.ToString() + ":有参有返回值 委托调用成功:DebugLogStr";

        Debug.Log(_Str);

        return _Str;
    }
}

委托基础执行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

什么是事件

    事件:事件是属于类的成员,事件就是委托的封装
    关键字:event
    定义:C# 中使用事件机制实现线程间的通信。
    总结:事件只能 Add、Remove  事件处理器不能赋值。并且事件只能执行 +=-=,不能=、不能外部触发事件。

事件模型的五个组成部分

    //事件模型的五个组成部分
    //1. 事件的拥有者【类】   ------> Custom类
    //2. 事件【event关键字】  ------> _OnOrder事件
    //3. 事件的响应者【类】      ------> ResponseEvent类
    //4. 事件的处理器【方法-受到约束的方法】   ------>Response方法
    //5. 事件的订阅关系【+=】        ------> +=
    //触发事件的对象称为事件发送者;接收事件的对象称为事件接收者。

如何声明一个事件(简略格式)

    //事件声明
    public event OrderEventHandler _OnOrder

事件声明完整格式

   //事件声明完整格式
    //声明一个委托变量
    //用途:用来存储、引用事件处理器的
    private OrderEventHandler _OrderEventHandler;

    //事件声明
    public event OrderEventHandler _OnOrder
    {
        //添加事件处理器的【添加器】和【移除器】
        add
        {
            _OrderEventHandler += value;
        }
        remove
        {
            _OrderEventHandler -= value;
        }
    }

    //内部执行逻辑
    public void Order()
    {
        //判断委托类型是否为空  是否有人订阅当前委托
        if (_OrderEventHandler != null)
        {
            //创建事件响应参数 实例
            OrderEnevetArgs _E = new OrderEnevetArgs();
            _E.EventAtgsStr = "事件处理A";
            _E.Price = 15;

            //参数: 事件发送者、拥有者  事件参数
            _OrderEventHandler(this, _E);
        }
    }

如何调用一个事件

    _MyCustom._OnOrder += _ResponseEvent.Response;

第一版完整代码

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

/// <summary>
/// 自定义事件
/// </summary>
public class CustomEvent_ZH : MonoBehaviour
{
    //事件模型的五个组成部分
    //1. 事件的拥有者【类】   ------> Custom类
    //2. 事件【event关键字】  ------> _OnOrder事件
    //3. 事件的响应者【类】      ------> ResponseEvent类
    //4. 事件的处理器【方法-受到约束的方法】   ------>Response方法
    //5. 事件的订阅关系【+=】        ------> +=
    //触发事件的对象称为事件发送者;接收事件的对象称为事件接收者。

    //创建事件拥有者的实列
    Custom _MyCustom = new Custom();

    //事件响应者
    ResponseEvent _ResponseEvent = new ResponseEvent();

    //事件是基于委托的
    //委托是事件的底层基础
    //事件是委托的上层建筑
    //1. 类型兼容 :事件需要使用委托类型来做一个约束

    private void Start()
    {
        _MyCustom._OnOrder += _ResponseEvent.Response;
    }
}

/// <summary>
/// 委托 
/// 如果使用  EventHandler 为后缀 说明当前委托类型是用来 使用事件处理的
/// 参数:事件拥有者  事件参数
/// </summary>
public delegate void OrderEventHandler(Custom _Custom, OrderEnevetArgs _E);

/// <summary>
/// 事件拥有者
/// </summary>
public class Custom
{
    //属性
    //账单
    public float Bill { get; set; }
    //资产
    public int MyProperty { get; set; }
    //
    public void PayTheBill()
    {
        Debug.Log("事件处理器" + Bill);
    }
    //事件声明简略格式
    public event OrderEventHandler _OnOrder;


    #region //事件声明完整格式

    //事件声明完整格式
    //声明一个委托变量
    //用途:用来存储、引用事件处理器的
    private OrderEventHandler _OrderEventHandler;

    //事件声明
    public event OrderEventHandler _OnOrder01
    {
        //添加事件处理器的【添加器】和【移除器】
        add
        {
            _OrderEventHandler += value;
        }
        remove
        {
            _OrderEventHandler -= value;
        }
    }

    //内部执行逻辑
    public void Order()
    {
        //判断委托类型是否为空  是否有人订阅当前委托
        if (_OrderEventHandler != null)
        {
            //创建事件响应参数 实例
            OrderEnevetArgs _E = new OrderEnevetArgs();
            _E.EventAtgsStr = "事件处理A";
            _E.Price = 15;

            //参数: 事件发送者、拥有者  事件参数
            _OrderEventHandler(this, _E);
        }
    }

    #endregion

}

/// <summary>
/// 事件参数传递
/// 如果一类的用途作为 EvenetArgs类 来使用  就要继承于EvenetArgs类(事件参数)
/// </summary>
public class OrderEnevetArgs : EventArgs
{
    //事件响应名字
    public  string EventAtgsStr { get; set; }

    //价格
    public float Price { get; set; }
}

/// <summary>
/// 事件响应者
/// </summary>
public class ResponseEvent
{
    internal void Response(Custom _Custom, OrderEnevetArgs _E)
    {
        //价格
        float _ResponsePrice = 0.0f;

        switch (_E.EventAtgsStr)
        {
            case "事件处理A":
                _ResponsePrice = _E.Price;
                break;

            case "事件处理B":
                _ResponsePrice = _E.Price + 3;
                break;

            case "事件处理C":
                _ResponsePrice = _E.Price + 6;
                break;

            default:
                break;
        }
        //账单
        _Custom.Bill += _ResponsePrice;
    }
}

最后完整代码

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

/// <summary>
/// 自定义事件
/// </summary>
public class CustomEvent_ZH : MonoBehaviour
{
    //事件模型的五个组成部分
    //1. 事件的拥有者【类】   ------> Custom类
    //2. 事件【event关键字】  ------> _OnOrder事件
    //3. 事件的响应者【类】      ------> ResponseEvent类
    //4. 事件的处理器【方法-受到约束的方法】   ------>Response方法
    //5. 事件的订阅关系【+=】        ------> +=
    //触发事件的对象称为事件发送者;接收事件的对象称为事件接收者。

    //创建事件拥有者的实列
    Custom _MyCustom = new Custom();

    //事件响应者
    ResponseEvent _ResponseEvent = new ResponseEvent();

    //事件是基于委托的
    //委托是事件的底层基础
    //事件是委托的上层建筑
    //1. 类型兼容 :事件需要使用委托类型来做一个约束

    private void Start()
    {
        _MyCustom._OnOrder += _ResponseEvent.Response;

        //事件拥有者的内部逻辑 触发事件
        _MyCustom.Order("事件触发器A", 15);
    }
}

/// <summary>
/// 事件拥有者
/// </summary>
public class Custom
{
    //属性
    //账单
    public float Bill { get; set; }
    //资产
    public int MyProperty { get; set; }


    //事件处理器
    public void PayTheBill()
    {
        Debug.Log("事件处理器" + Bill);
    }

    //事件声明简略格式
    public event EventHandler _OnOrder;

    //内部执行逻辑
    public void Order(string _Name, float _Price)
    {
        //如果事件不为空
        if (_OnOrder!=null)
        {
            OrderEnevetArgs _OrderEnevetArgs = new OrderEnevetArgs();
            _OrderEnevetArgs.EventAtgsStr = _Name;
            _OrderEnevetArgs.Price = _Price;

            //参数: 事件发送者、拥有者  事件参数
            _OnOrder(this, _OrderEnevetArgs);
        }

    }

}

/// <summary>
/// 事件参数传递
/// 如果一类的用途作为 EvenetArgs类 来使用  就要继承于EvenetArgs类(事件参数)
/// </summary>
public class OrderEnevetArgs : EventArgs
{
    //事件响应名字
    public  string EventAtgsStr { get; set; }

    //价格
    public float Price { get; set; }
}

/// <summary>
/// 事件响应者
/// </summary>
public class ResponseEvent
{
    internal void Response(object sender, EventArgs e)
    {
        //价格
        float _ResponsePrice = 0.0f;
        // as 类型转换
        Custom _Custom = sender as Custom;

        OrderEnevetArgs _OrderEnevetArgs = e as OrderEnevetArgs;

        switch (_OrderEnevetArgs.EventAtgsStr)
        {
            case "事件处理A":
                _ResponsePrice = _OrderEnevetArgs.Price;
                break;

            case "事件处理B":
                _ResponsePrice = _OrderEnevetArgs.Price + 3;
                break;

            case "事件处理C":
                _ResponsePrice = _OrderEnevetArgs.Price + 6;
                break;

            default:
                break;
        }
        //账单
        _Custom.Bill += _ResponsePrice;
    }
}

大总结!!!(敲黑板)

委托和事件的关系?
答:事件不是委托类型的字段也不是一种特殊类型的字段。
	事件只是委托的包装器、限制器,限制外界对委托类型的字段访问,但并不是委托字段的本身。
为什么要使用委托类型来声明事件?
答:因为委托类型可以完美保存、记录、存储,并响应事件。

暂时先这样吧,如果有时间的话就会更新,实在看不明白就留言,看到我会回复的。
路长远兮,与君共勉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maddie_Mo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值