Appearance
Action
一句话理解
Action 是 C# 内置的一种 delegate,专门用来保存“没有返回值的方法”。
你可以把它理解成:
我先把“等会儿要做的事”存起来,到了合适时机再调用它。
最基础写法
c
using System;
using UnityEngine;
public class ActionDemo : MonoBehaviour
{
private Action onDead;
private Action<int> onDamaged;
private void Start()
{
onDead = ShowGameOver;
onDamaged = RefreshHp;
onDead?.Invoke();
onDamaged?.Invoke(20);
}
private void ShowGameOver()
{
Debug.Log("显示游戏结束界面");
}
private void RefreshHp(int damage)
{
Debug.Log("扣血:" + damage);
}
}这里你要抓住 3 点:
Action 保存的是无参数、无返回值的方法。 Action<int> 保存的是接收一个 int 参数、无返回值的方法。 ?.Invoke() 的意思是:如果里面有方法,就调用;如果是 null,就什么也不做。
Action 的常见形态
c
Action a; // 无参数,无返回值
Action<int> b; // 一个 int 参数,无返回值
Action<string, int> c; // 两个参数,无返回值
Action<float, bool> d; // 两个参数,无返回值注意:Action 永远没有返回值。需要返回值时用 Func。
c
Func<int, bool> checkHp; // 传入 int,返回 boolUnity 里最常用的 Action 场景
最常见是“通知别人某件事发生了”。
c
using System;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
public event Action<int> OnDamaged;
public void TakeDamage(int damage)
{
OnDamaged?.Invoke(damage);
}
}另一个脚本订阅它:
c
public class HealthUI : MonoBehaviour
{
public PlayerHealth player;
private void OnEnable()
{
player.OnDamaged += RefreshUI;
}
private void OnDisable()
{
player.OnDamaged -= RefreshUI;
}
private void RefreshUI(int damage)
{
Debug.Log("刷新血条,扣血:" + damage);
}
}这里的思路是:
PlayerHealth 不需要知道 UI 怎么刷新。 它只负责发出“我受伤了”的通知。 HealthUI 自己订阅这个通知,然后做自己的事。
这就是 Action 很重要的地方:让两个系统少互相依赖。
Action 和 event 的区别
Action<int> OnDamaged; 是一个普通委托字段,外部脚本可能直接覆盖它或调用它。 event Action<int> OnDamaged; 更安全,外部通常只能 += 订阅、-= 取消,不能随便调用。
Unity 项目里,公开通知通常更推荐:
c
public event Action<int> OnDamaged;三个新手坑
- 需要返回值时不要用
Action,用Func。 - 订阅了事件,记得在
OnDisable里取消订阅。 - 匿名 lambda 不好取消订阅,重要监听最好保存成方法或变量。
官方参考链接:
Microsoft - System.ActionMicrosoft - System.ActionMicrosoft - DelegatesMicrosoft - EventsMicrosoft - FuncUnity - UnityActionUnity - UnityEvent