对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

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Unity中反射、委托、事件、ActionFunc的使用,我可以给你一些简单的例子。但需要注意的是,反射虽然功能强大,但是使用不当会影响程序的性能,所以在实际开发中要谨慎使用。 反射: 反射可以动态地获取和调用对象的方法和属性,这在一些特定的场景下非常有用。以下是一个简单的使用反射获取对象属性值的脚本示例: ``` using System.Reflection; using UnityEngine; public class ReflectionExample : MonoBehaviour { public int myInt = 10; private void Start() { PropertyInfo propertyInfo = typeof(ReflectionExample).GetProperty("myInt"); Debug.Log("myInt = " + propertyInfo.GetValue(this)); } } ``` 上面的代码中,我们使用了反射获取了myInt属性的值,并打印出来。 委托委托可以用来代表一个方法,并且可以传递给其他方法,这在许多场景下非常有用。以下是一个简单的使用委托调用方法的脚本示例: ``` using UnityEngine; public class DelegateExample : MonoBehaviour { public delegate void MyDelegate(string message); public MyDelegate myDelegate; private void Start() { myDelegate = LogMessage; myDelegate("Hello World"); } private void LogMessage(string message) { Debug.Log(message); } } ``` 上面的代码中,我们定义了一个委托类型MyDelegate,并且将LogMessage方法赋值给myDelegate变量。然后通过调用myDelegate来调用LogMessage方法,并将"Hello World"作为参数传递给LogMessage方法。 事件: 事件是一种特殊的委托类型,只能通过+=和-=来添加和移除方法,这样可以确保事件只能在特定的时刻被调用。以下是一个简单的使用事件的脚本示例: ``` using UnityEngine; public class EventExample : MonoBehaviour { public delegate void MyDelegate(); public event MyDelegate myEvent; private void Start() { myEvent += LogMessage; myEvent(); } private void LogMessage() { Debug.Log("Event Fired"); } } ``` 上面的代码中,我们定义了一个事件类型MyDelegate,并且将LogMessage方法添加到事件myEvent中。然后通过调用myEvent来调用LogMessage方法。 ActionFuncActionFunc是两种预定义的委托类型,分别代表不带参数和带一个参数并且有返回值的方法。以下是一个简单的使用ActionFunc的脚本示例: ``` using UnityEngine; public class ActionFuncExample : MonoBehaviour { private void Start() { Action myAction = LogMessage; myAction(); Func<int, int> myFunc = AddOne; int result = myFunc(10); Debug.Log("Result = " + result); } private void LogMessage() { Debug.Log("Action Called"); } private int AddOne(int number) { return number + 1; } } ``` 上面的代码中,我们定义了一个Action类型的委托myAction,并且将LogMessage方法赋值给myAction变量。然后通过调用myAction来调用LogMessage方法。同样,我们也定义了一个Func类型的委托myFunc,并且将AddOne方法赋值给myFunc变量。然后通过调用myFunc来调用AddOne方法,并将10作为参数传递给AddOne方法,并将返回值打印出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值