对delegate、Func、Action、event、UnityEvent、UnityAction委托一族的总结

9 篇文章 0 订阅
9 篇文章 0 订阅

对委托相关知识的总结,参考了一些博客再加上了自己的理解。

delegate、Func、Action、event、UnityEvent、UnityAction

委托

一种可用于封装命名或者匿名方法的引用类型。

它的存在说明变量不仅能存储值,对象的引用,还能存方法。只不过声明时前面加个delegate。与函数指针不是同个概念。

类似于 C++ 中的函数指针,而且是类型安全和可靠的。

可用于简化代码,实现观察者模式。

一、自定义委托类型:

delegate 返回值 方法名(参数)

二、.NET自带泛型委托类型:

省去自定义委托类型

1、Action< T >:只能委托无返回值的方法

2、Func< T , Result >只能委托有返回值的方法,可有参数数量:0~5

// 一、显式委托声明 -- 定义一个签名:
delegate double MathFunc(double num);

class DelegateTest
{
    // 符合委托声明的常规方法
    double Double(double input)
    {
        return input * 2;
    }

	void Output(double result)
	{       
		Console.WriteLine(result);
	}

    void Main()
    {
        // 1、使用一个命名方法实例化委托类型
        MathFunc mf1 = Double;
        // 调用委托实例
        double res = mf1(233);

        // 2、用匿名方法来实例化委托类型
        mf1 = delegate(double input)
        {
            return input * input;
        };
        res = mf1(233);

        // 3、用Lambda表达式来实例化委托类型
        mf1 = s => s * s * s;
        res = mf1(4);
        
        //二、1、实例化Func<T, TResult>、Action<T>委托类型(省去显式自定义委托)
        Func<double, double> mf2 = Double;
        Action<double> mf3 = Output;
        
        // 2、用匿名方法
        mf2 = delegate(double input)
        {
            return input * input;
        };
        // 3、用Lambda表达式
        mf2 = s => s * s * s;
        
        res = mf2(233);
    }
}

三、多重委托:event

相当于一个方法的容器,调用event时,便调用容器中的所有方法。因此可用于实现观察者模式。

可用+=、-=增删相应的委托类型的方法。直接以方法的形式调用,或者以Invoke()调用。

注意,在方法内部声明event会报错。

示例代码:

class EventTest
{   
    //1、声明包含Func<double, double>类型的委托的event
    event Func<double, double> mfe; 
    void Main()
    {
        Func<double, double> ma1 = s => s * s;
        Func<double, double> ma2 = s => s * s * s; 
        
        //2、增加包含的方法
        mfe += ma1;
        mfe += ma2;
        
        //3、调用所有方法
        double res = mfe(233);  
    }
}

使用event实现发布-订阅模式:

Idol.cs:发布者

using UnityEngine;

public class Idol : MonoBehaviour {
    public delegate void IdolBehaviour(string behaviour);
    //设置为静态以让粉丝们能订阅、退订(增删委托方法)
    public static event IdolBehaviour IdolDoSomethingHandler;

    private void Start()
    {
        //Idol 决定搞事了, 如果他还有粉丝的话, 就必须全部都通知到
        if (IdolDoSomethingHandler != null)
        {
        	//所有的粉丝都接收到消息(参数),并行动(执行)
            IdolDoSomethingHandler("Idol give up writing.");
        }
    }
} 

SubscriberA.cs:订阅者A

using UnityEngine;

public class SubscriberA : MonoBehaviour {
    /// <summary>
    /// OnEnable在该脚本被启用时调用,你可以把它看做路转粉的开端
    /// </summary>
    private void OnEnable()
    {
        //粉丝通过订阅偶像来获取偶像的咨询, 并在得到讯息后执行相应的动作
        Idol.IdolDoSomethingHandler += LikeIdol;
    }

    /// <summary>
    /// OnEnable在该脚本被禁用时调用,你可以把它看做粉转路的开端
    /// </summary>
    private void OnDisable()
    {
        Idol.IdolDoSomethingHandler -= LikeIdol;
    }

    /// <summary>
    /// 粉丝A是一个脑残粉
    /// </summary>
    /// <param name="idolAction"></param>
    public void LikeIdol(string idolAction)
    {
        print(idolAction + " I will support you forever!");
    }
} 

SubscriberB.cs:订阅者B

using UnityEngine;

public class SubscriberB : MonoBehaviour {
    /// <summary>
    /// OnEnable在该脚本被启用时调用,你可以把它看做路转粉的开端
    /// </summary>
    private void OnEnable()
    {
        //粉丝通过订阅偶像来获取偶像的咨询, 并在得到讯息后执行相应的动作
        Idol.IdolDoSomethingHandler += HateIdol;
    }

    /// <summary>
    /// OnEnable在该脚本被禁用时调用,你可以把它看做粉转路的开端
    /// </summary>
    private void OnDisable()
    {
        Idol.IdolDoSomethingHandler -= HateIdol;
    }

    /// <summary>
    /// 粉丝B是一个无脑黑
    /// </summary>
    /// <param name="idolAction"></param>
    public void HateIdol(string idolAction)
    {
        print(idolAction + " I will hate you forever!");
    }
} 

四、Unity的再包装:UnityAction、UnityEvent

Unity独有的这两个类分别对应Action,event。与Event不同的是,UnityEvent序列化后,可以在Editor面板上显示,增删包含的方法(UnityAction)。

Unity所使用的监听器(例如OnClick)都是UnityEvent类。

作为一个对象,而不是一个有特殊待遇的event。它要按对象的方式来使用。可继承。

AddListener():注册UnityAction

RemoveListener:取消注册UnityAction

Invoke():调用所有UnityAction

示例代码:

using UnityEngine;
using UnityEngine.Events;

//使用Serializable序列化IdolEvent, 否则无法在Editor中显示
[System.Serializable]
public class IdolEvent : UnityEvent<string> {
	//......
}

public class Idol : MonoBehaviour {
    public IdolEvent idolEvent;

    private void Start()
    {
        if (idolEvent == null)
        {
            idolEvent = new IdolEvent();
        }
        idolEvent.Invoke("Idol give up writing.");
    }
} 

使用后的Editor面板:
在这里插入图片描述
参考
https://docs.unity3d.com/ScriptReference/Events.UnityEvent.html
https://blog.csdn.net/qq_28849871/article/details/78366236
https://blog.csdn.net/linzhonglong/article/details/81131097

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值