一 匿名函数
1、 什么是匿名函数
顾名思义,就是没有名字的函数, 本质还是函数,只不过没有名字。匿名函数的使用主要是配合委托和事件进行使用,脱离委托和事件是不能使用匿名函数的。
2、 基本语法
delegate(参数列表)
{
函数体;
};
3、 使用
不能单独使用,必须要有委托或者方法来装载匿名函数。实际就是一个委托类型的变量,可把它当作参数和返回值在函数之间穿梭。
using System;
using UnityEngine;
namespace 匿名函数学习
{
public class anonymous : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 3 使用
// 1 无参无返回值
// 申明匿名函数,并把它放到 无参无返回值的系统自带委托中
// 这个地方只是申明匿名函数而已,还没有真正调用
Action a= delegate ()
{
Debug.Log("匿名函数逻辑");
};
// 真正调用匿名函数
a();
// 2 有参数
Action<int, string> a2 = delegate (int a, string b)
{
Debug.Log(a);
Debug.Log(b);
};
a2(100, "chenzhuo");
// 3 有返回值
Func<string> f = delegate ()
{
return "123";
};
Debug.Log(f());
// 4 一般情况会作为函数参数传递或者作为函数返回值
// 参数传递
Test t = new Test();
Action ac = delegate ()
{
Debug.Log("随参数传入得匿名函数逻辑");
};
// 先用个委托把匿名函数存起来,在作为参数进行传递
t.Dosomthing(50, ac);
// 懒得存,一步到位,
t.Dosomthing(100, delegate ()
{
Debug.Log("随参数传入得匿名函数逻辑");
});
// 作为函数返回值
Action ac2= t.GetFun();
// 把匿名函数返回出来在调用
ac2();
// 一步到位
t.GetFun()();
#endregion
#region 4 匿名函数的缺点
// 因为匿名函数没有名字 所以没有办法指定移除某一个匿名函数
Action ac3 = delegate ()
{
Debug.Log("匿名函数一");
};
ac3 += delegate ()
{
Debug.Log("匿名函数二");
};
ac3();
// 故此,不能通过-= 来移除对应的匿名函数
// 此匿名函数,非彼匿名函数
// 智能通过
ac3 = null; // 来清除所有匿名函数
#endregion
Test test = new Test();
// 一个函数传入一个整数,与之返回一个函数的传入参数相乘。
Debug.Log(test.TestFun(10)(20)) ;
}
}
class Test
{
public Action action= null;
public Func<int,int> TestFun(int a)
{
return delegate (int b)
{
return a *b;
};
}
public void Dosomthing(int a, Action fun)
{
// 匿名函数被调用
fun();
}
public Action GetFun()
{
return delegate () { Debug.Log("函数内部返回一个匿名函数逻辑"); } ;
// return TestFun;
}
}
}
总结
- 匿名函数 就是没有 名字的函数
- 固定写法:delegate(参数列表){};
- 主要在 委托传递和存储时,不用从新定义函数,可以直接使用匿名函数
- 缺点:没有办法指定移除
二 lambad表达式
1、什么是lambad表达式
可以将lambad表达式理解为匿名函数的简写,它除了写法不同外,使用上和匿名函数一模一样都是和委托或者事件配合使用的。
2 、lambad 表达式语法
(参数列表) =>
{
函数体;
};
3 、lambad表达式使用
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class Lambda : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 2 lambad 表达式语法
// (参数列表) =>
// {
// 函数体
// };
#endregion
#region 3 lambad 使用
#endregion
// 1 无参无返回值
Action action = () =>
{
Debug.Log("lambad表达式");
};
action();
// 2 有参数
Action<string> action2 = (string str) =>
{
Debug.Log("lambad表达式"+str);
};
action2("1123");
// 3 甚至参数类型都可以省略 参数类型和委托或者事件容器一致
Action<int> action3 = (value) =>
{
Debug.Log("省略参数类型的写法"+value);
};
action3(200);
// 4 有返回值
Func<string, int> a4 = (value) =>
{
Debug.Log("有返回值的lambad表达式");
return 1;
};
Debug.Log(a4("1123"));
}
}
总结:
- 匿名函数的特殊用法就是lambad表达式
- 固定写法就是(参数列表)=>{ };
- 参数列表可以直接省略参数类型
- 主要在委托传递和存储时为了方便可以直接使用匿名函数或者lambad表达式
- 缺点:无法指定移除
三 闭包
1、什么是闭包
- 内层的函数可以引用包含在它外层的函数的变量
- 即使外层函数的执行已经终止
- 注意: 该变量提供的值并非变量创建的值,而是在父函数范围内的最终值(去代码中理解)
2、闭包的使用
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class Lambda : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 闭包
// 内层的函数可以引用包含在它外层的函数的变量
// 即使外层函数的执行已经终止
// 注意: 该变量提供的值并非变量创建的值,而是在父函数范围内的最终值
Test test = new Test();
test.DoSomething();
#endregion
}
class Test
{
// 声明一个事件
public event Action action;
public Test()
{
int value = 100;
// 这里就形成了闭包 可以在内函数中去引用外部函数的变量
// 因为 当构造函数执行完毕时 其中声明的临时变量value 生命周期被改变了
action = () =>
{
Debug.Log(value); // 打印100
};
for (int i = 0; i < 10; i++)
{
action += ()=>
{
// 注意: 该变量提供的值并非变量创建的值,而是在父函数范围内的最终值
Debug.Log(i); // 打印的结果都是 10
};
}
for (int i = 0; i < 10; i++)
{
// 要解决这个问题,就在这个地方 声明一个临时变量 index,每次循环都会声明一个新的 index 临时变量
int index = i;
action += () =>
{
Debug.Log(index); // 打印的结果为 0,1,2,3,4。。。。9
};
}
}
public void DoSomething()
{
action();
}
}
}
总结:
- 内层的函数(主要指:委托和事件)可以引用包含在它外层的函数的变量
- 注意,使用闭包时:临时变量的生命周期的变化。
- 理解:该变量提供的值并非变量创建的值,而是在父函数范围内的最终值。