Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述

Lambda表达式

Lambda表达式本质上就是定义匿名函数

1 Lamba表达式基本结构

(形参列表) => {函数体};   // 当形参只有一个时可以省去"()", 当函数体内只有一段语句时可以省去"{}"

2 将函数改写为Lambda表达式

2.1 无返回值无参数时

void Func1()
{
	Debug.Log("Func1 call");
}
// Lambda表达式:
() => {Debug.Log("Func1 call");Debug.Log("Func100 call");};
() => Debug.Log("Func1 call");   // 如果匿名函数内部只有一段话,可以省去"{}"

2.2 有参数无返回值时

void Func2(int a)
{
    a *= a;
    Debug.Log(a);
}
// Lambda表达式:
(a) => {a *= a; Debug.Log(a);};
a => {a *= a; Debug.Log(a);};

2.3 有返回值有参数时

int Func3(int a, int b)
{
    return a + b;
}
// Lambda表达式
int res = (a, b) => {return a + b;};  // 存在返回值时不可以省略"{}"

委托Delegate

委托可以理解为存储方法的数组,通过委托可以将几个具有相同形参类型和返回值类型的方法加入到一个委托中一并执行

1 定义委托

private int delegate VoidDelegate(int a, int b);   // 括号内为传递的参数

2 实例化委托

VoidDelegate d1; 
VOidDelegate d1 = new VoidDelegate(Func1);   // 如果利用new关键字定义委托,同时需要为其赋初值

3 向委托中添加/删除函数

d1 = Func1;    // 添加第一个函数时需要直接赋值
d1 += Func2;   // 注意这里只能传递一个函数名进去,如果函数名后面加了括号,就会执行该函数一次,这是我们不期望的
d1 += Func3;   
d1 -= Func1;

4 调用委托

d1();    // 直接调用
d1.Invoke(a, b)   // 利用Invoke调用

完整代码

public delegate int IntDelegate(int a, int b);
private void IntDelegateTest()
{
    IntDelegate id;
    id = (a, b) => { return a + b; };
    id += (a, b) => { return a - b; };
    id += (a, b) => { return a * b; };
    int res = id.Invoke(1, 2);   // int res = id(1, 2);
    Debug.Log(res);
}
// 返回值为2,当委托存在返回值时,就只会返回最后加进去的函数的返回值

输出结果:
在这里插入图片描述

委托的使用类内和类外无差别

事件Event

事件可以理解为委托的一个实例(不太严谨),在类的内部声明事件,必须先声明该事件对应的委托类型

同时事件不仅可以添加函数进去,还可以加入委托

public delegate void VoidDelgate(int a);
public static event VoidDelgate voidEvent;
private void VoidEventTest()
{
    // 先定义一个委托
    VoidDelgate vd;
    vd = a => Debug.Log(a);
    vd += a => Debug.Log(a * a);

    // 向事件内添加委托和函数
    voidEvent = vd;
    voidEvent += a => Debug.Log(a - 1);
    voidEvent += a => Debug.Log(a + 1);
    voidEvent(6);
}

输出结果:

Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第1张图片

事件与委托的区别:

  • 委托创建时会定义方法的类型(是否有无参数、有无返回值)
  • 事件的创建需要一个委托才能声明(因为事件就是委托的实例)
  • 委托可以在任何类中或类外声明,但是事件只能在类中声明(类型跟实例,实例要运行所以要在类里面咯)
  • 事件只能在当前声明的类中调用,但是可以在其他类中为其添加/删除函数,无论将事件设置成public还是static其他类都无法调用

Action

Action可以理解为系统定义好的带泛型的delegate,Action是无返回值的

要使用Action需要引用头文件

using System;

Action的泛型T代表参数,T内可以传多个参数

private void ActionTest()
{
    Action action;   // 无参的Action
    action = () => Debug.Log("action use once");
    action += () => Debug.Log("action use twice");
    action();

    Action<int, string> action2;   // 有多个参数的Action
    action2 = (a, b) => Debug.Log("name: " + b + "\tage: " + a.ToString());
    action2 += (a, b) => Debug.Log("name: " + b + "\tage: " + (a + 1).ToString());
    action2(18, "Ousun");
}

输出结果:
Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第2张图片

Func

Func可以理解为系统定义好的带泛型的delegate,Func是有返回值的

要使用Func需要引用头文件

using System;

Func的前n-1个泛型代表参数, 最后一个泛型代表返回值类型

private void FuncTest()
{
    Func func;
    func = (a) => { Debug.Log(a); return a; };
    func += (a) => { a += 1; Debug.Log(a); return a; };
    func += (a) => { a += 2; Debug.Log(a); return a; };
    int res = func(1);
    Debug.Log("res = " + res.ToString());
}

输出结果:
Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第3张图片

UnityAction

UnityAction是Unity对C#中Action的再封装,是更适合再Unity中使用的一种泛型委托,用法和Action一样

需要包含头文件:

using UnityEngine.Events;
private void UnityActionTest()
{
    UnityAction action;   // 无参的Action
    action = () => Debug.Log("action use once");
    action += () => Debug.Log("action use twice");
    action();

    UnityAction<int, string> action2;   // 有多个参数的Action
    action2 = (a, b) => Debug.Log("name: " + b + "\tage: " + a.ToString());
    action2 += (a, b) => Debug.Log("name: " + b + "\tage: " + (a + 1).ToString());
    action2(18, "Ousun");
}

输出结果:

Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第4张图片

UnityEvent

UnityEvent可以在面板中添加监听事件,也可以在代码中添加监听事件或UnityAction

public UnityEvent<int, string> myEvent;

UGUI中的Buttom点击事件,就继承自UnityEvent,可以将UnityEvent显示在监视器面板中
Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第5张图片

在代码中调用event,只能使用Invoke方法调用,同时,UnityEvent内添加的方法可以是UnityAction

用 AddListener 和 RemoveListener 分别为事件添加和移除方法

public UnityEvent<int, string> myEvent;
private void UnityEventTest()
{
    myEvent.AddListener((a, b) => 
    { 
    	Debug.Log("name: " + b + "\tage: " + a.ToString()); 
    });
    myEvent.AddListener((a, b) =>
    {
    	Debug.Log("name: " + b + "\tage: " + (a + 1).ToString());
    });
    myEvent.Invoke(18, "Ousun");
}

输出结果:

在这里插入图片描述

配合监视器面板使用:

监视器如下:

Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第6张图片

添加的相关函数如下:

public void InspectorEvent(int a, string b)
{
	Debug.Log("InspectorEvent is called");
}

public void InspectorEvent2(int a, string b)
{
	Debug.Log("InspectorEvent2 is called");
}

再次调用上面的UnityEventTest()函数,输出结果如下:

Unity/C#知识点 -- Lambda表达式、委托Delegate、事件Event、Action、Func、UnityAction、UnityEvent综述_第7张图片
参考:【Unity知识点】通俗解释delegate,事件event,Action,Func和UnityAction,UnityEvent

你可能感兴趣的:(Unity,c#,unity,学习,游戏引擎,游戏程序)