Lambda表达式
Lambda表达式本质上就是定义匿名函数
(形参列表) => {函数体}; // 当形参只有一个时可以省去"()", 当函数体内只有一段语句时可以省去"{}"
void Func1()
{
Debug.Log("Func1 call");
}
// Lambda表达式:
() => {Debug.Log("Func1 call");Debug.Log("Func100 call");};
() => Debug.Log("Func1 call"); // 如果匿名函数内部只有一段话,可以省去"{}"
void Func2(int a)
{
a *= a;
Debug.Log(a);
}
// Lambda表达式:
(a) => {a *= a; Debug.Log(a);};
a => {a *= a; Debug.Log(a);};
int Func3(int a, int b)
{
return a + b;
}
// Lambda表达式
int res = (a, b) => {return a + b;}; // 存在返回值时不可以省略"{}"
委托可以理解为存储方法的数组,通过委托可以将几个具有相同形参类型和返回值类型的方法加入到一个委托中一并执行
private int delegate VoidDelegate(int a, int b); // 括号内为传递的参数
VoidDelegate d1;
VOidDelegate d1 = new VoidDelegate(Func1); // 如果利用new关键字定义委托,同时需要为其赋初值
d1 = Func1; // 添加第一个函数时需要直接赋值
d1 += Func2; // 注意这里只能传递一个函数名进去,如果函数名后面加了括号,就会执行该函数一次,这是我们不期望的
d1 += Func3;
d1 -= Func1;
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,当委托存在返回值时,就只会返回最后加进去的函数的返回值
委托的使用类内和类外无差别
事件可以理解为委托的一个实例(不太严谨),在类的内部声明事件,必须先声明该事件对应的委托类型
同时事件不仅可以添加函数进去,还可以加入委托
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);
}
输出结果:
事件与委托的区别:
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");
}
Func可以理解为系统定义好的带泛型的delegate,Func是有返回值的
要使用Func需要引用头文件
using System;
Func
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());
}
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");
}
输出结果:
UnityEvent可以在面板中添加监听事件,也可以在代码中添加监听事件或UnityAction
public UnityEvent<int, string> myEvent;
UGUI中的Buttom点击事件,就继承自UnityEvent,可以将UnityEvent显示在监视器面板中
在代码中调用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");
}
输出结果:
配合监视器面板使用:
监视器如下:
添加的相关函数如下:
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知识点】通俗解释delegate,事件event,Action,Func和UnityAction,UnityEvent