委托
- 可以看做
函数指针
,存放函数的容器的变量
- 这个指针存放的函数
参数
和返回值
一致,函数模板
- 委托类型在作为参数传递时,相当于直接将参数返回值一样的函数的返回值传进去
- 因此可以用在多个函数功能类似的情况下
- 先写一个公用的功能,调用时直接传入委托
- 不同的地方拎出来一个一个写
- 符合函数模板可以通过
+=
添加给委托,委托执行时注册的函数都会执行
- 由于委托可以被其他委托
赋值
,存在被修改的风险
将函数作为参数传递时,在另外一个类触发该委托返回值时,可以直接触发这个函数,只关心该函数,而不需要知道传来的类
delegate创建
1 2
| public delegate void TestDelegate(); public delegate bool TestBoolDelegate(int i);
|
Action创建
Action |
无参无构造函数的委托 |
Action, Action |
有参数委托 |
1 2
| public Action testAction; public Action<int ,float> testInFloatAction;
|
Func创建
Func |
返回值为T类型的委托 |
Func, Func |
第一个类型返回值,后面都是参数 |
1 2
| public Func<bool> testFunc; public Func<int, bool> testIntBoolFunc;
|
创建和初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class Testing : MonoBehaviour { public delegate void TestDelegate(); public delegate bool TestBoolDelegate(int i); private TestDelegate testDelegateFunction; private TestBoolDelegate testBoolDelegateFunction; public Action testAction; public Action<int ,float> testInFloatAction; public Func<bool> testFunc; public Func<int, bool> testIntBoolFunc; private void Start() { testDelegateFunction = MyTestDelegateFunction; testDelegateFunction += MySecondTestDelegateFunction; testDelegateFunction(); testDelegateFunction = delegate(){ Debig.log(" ");}; testDelegateFunction = () => { Debig.log(" "); }; testDelegateFunction = (int i) => { return i < 5; }; testDelegateFunction += () => { Debig.log(" "); }; testInFloatAction = (int i, float f) => { Debig.log(" "); }; testFunc = () => false; testIntBoolFunc = (int i) => { return i < 5; }; testBoolDelegateFunction = MyThirdTestDelegateFunction; MyThirdTestDelegateFunction(); } private void MyTestDelegateFunction() { } private void MySecondTestDelegateFunction() { } private bool MyThirdTestDelegateFunction(int i) { return i; } }
|
事件
EventHandler
delegate
Action
UnityEvent
创建和初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| # Scripts01
using UnityEngine.Events; public class TestingEvents:Monobehaviour { public event EventHandler<OnSpacePressedEventArgs> OnSpacePressed; public class OnSpacePressedEventArgs : EventArgs { public int count; } public event TestEventDelegate OnFloatEvent; public delegate void TestEventDelegate(float f); public event Action<bool, int> OnActionEvent; public UnityEvent OnUnityEvent; private int Count; void Start() { }
void Update() { if (Input.GetKeyDown(KeyCode.Space)) {
Count++; OnSpacePressed?.Invoke(this, new OnSpacePressedEventArgs {count = Count}; OnFloatEvent?.(0.5f); OnActionEvent?.(true, 56); OnUnityEvent?.(); } } }
#Scripts02 public class TestEventSub: MonoBehaviour { void Start() { TestEvent testEvents = GetComponent<TestEvents>(); testEvents.OnSpacePressed += Test_OnSpacePressed; testEvents.OnFloatEvent += Test_OnFloatEvent; testEvents.OnActionEvent += Test_OnActionEvent; } void Test_OnSpacePressed(object sender, testEvents.OnSpacePressedEventArgs e) { Debug.log("Space" + e.count); } void Test_OnFloatEvent(float f) { Debug.log("Float:" + f); } void Test_OnActionEvent(bool args1, int args2) { Debug.log(args1 + args2); } }
|
闭包
一个匿名函数引用到外部变量,就会造成闭包
。C#为了实现这一点会生成一个匿名类来保存用到的外部变量,因此当调用这个闭包时,首先会实例化一个副本
,同时会采用外部变量实际值来初始化这个副本,最终致使会在堆
上分配内存。也就是说闭包就一定会产生内存分配
(产生GC)。
- 实现:内函数作为外函数的返回值,再将外函数赋给一个变量,再使用这个变量调用,这样就直接调用内函数而没有经过外函数
- 有函数嵌套
- 内部函数引用外部作用域的变量参数(C#的内部函数就是lamda表达式)
- 外部函数的返回值是函数
- 创建一个对象函数,让其一直在,而不是外部全局变量
使用匿名方法,最好将需要的外部变量作为参数传递,避免直接使用产生闭包
踩坑
From:https://blog.csdn.net/yinfourever/article/details/122583812,https://blog.csdn.net/deatharthas/article/details/106606754?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-8-106606754-blog-105412263.235