emmmm先附上一个讲得不错的链接:Difference Between Delegates and Events in C#

Delegates(代表/委托)

  • Delegate: a variable that holds a method or several methods.

来看一下一个例子。在这里我们先声明了一个delegate,这是装有一个输入类型为Color的参数并且返回为空的方法的数据类型。我们像声明一个变量或类一样声明一个delegate变量onColorChange
。然后我们再来写两个方法一个是带有一个传入Color类型参数的方法UpdateColor(),另一个是啥都没有的Task(),我们可以发现我们可以将UpdateColor赋给onColorChange,但无法将Task赋给onColorChange,因为签名不匹配。同样的,传入参数数量不一致也不行,传回类型不一样也不行。我们就假设有个宗门吧,把Delegate比作宗门的掌门吧,掌门代表了整个宗门,掌门都会制定表示宗门的令牌也就是Signature,上面是代表标志啊花纹啊特殊能量印记啊(返回类型和输入参数),只有全部符合才能说“啊你是这个宗门的”,有一点点不一致就是伪造啦就不是这个宗门的(不用宗门功法举例是因为宗门功法是可以被外人偷学的(bushi 。然后调用(call/invoke)的话就把这个delegate变量当作方法一样调用就好了。
注意: delegate是作为函数指针来引用方法的

 public class MainForDelegates : MonoBehaviour{// define a signature for delegatepublic delegate void ChangeColor(Color newColor);// use delegatepublic ChangeColor onColorChange; // we can assign onColorChange to any method that matches this delegate signature.private void Start(){onColorChange = UpdateColor;onColorChange(Color.blue); //Invoke//onColorChange = Task; //ERROR}public void UpdateColor(Color newColor){Debug.Log("change color to: " + newColor.ToString());}public void Task(){}}
  • Multicast(多播) delegates: stack on these task and invoke them all at once. 将拥有相同签名的方法添加给delegate变量,通过delegate进行一次性同时调用。就比如说我们的掌门可以发出多条命令,比如进攻啊埋伏啊疗伤后援啊。(其实不太明白为什么这边存储方式是说stack,栈的话是后进先出啊,可以测试结果看是先进先出???
     public delegate void TaskToDo();public TaskToDo tasks;private void Start(){// add all u want to calltasks += Task1;tasks += Task2;tasks += Task3; tasks -= Task1;//removeif(tasks != null){tasks();}}public void Task1(){Debug.Log("Task1!");}public void Task2(){Debug.Log("Task2!");}public void Task3(){Debug.Log("Task3!");}

Events(事件)

  • events: specialized delegates, allowing us to create a type of broadcast(广播) system that allows other classes and objects to subscribe or de-subscribe to our delegates. 也就是说触发事件,让多个物体参与然后执行一些事情。就还是延续上面的宗门相关的例子,比如现在有一场宗派大战(event),好多个宗门(class)都要参加。大战开打时,每个宗门的掌门(delegate)就要开始号令本门弟子(符合signature)执行战斗(methods)。

举个例子,我们现在要通过一个按钮,当我点击它的时候,我希望当我点击这个按钮时,所有场景里的小方块都要变色。在之前我们都怎么做,获取场景里的小方块然后写个判断,当我按下按钮时foreach每个方块执行变色代码对吧。

  • 按钮: 右键->UI->Button. 在Inspector的Button的这个地方,我们可以对按下按钮要触发的函数进行设置。左边是脚本附着的Obj,右边是要调用的脚本里的方法

如果用event相关的话要怎么做?
首先我们先声明一个delegate用于引用点击的函数,然后声明一个event,要注意声明event时要把参与者,也就是delegate是哪些范围的也要说明,就像宗门间的大比只有宗门可以参加,魔教啊散修组织啊就不参加。然后我们要做个判断是否有宗门参加了这次宗门大比,有的话,我们就可以调用这个event方法。调用event方法的方式和调用普通的方法一样。这边涉及到设计模式:观察者模式

  • Observer Pattern(观察者模式): subscribers and listeners. 在这个例子中,listeners是小方块,它们可以订阅方法onClick,当我们按下按钮时,我们要判断有没有listener订阅了onClick。
    public class MainForEvent : MonoBehaviour{public delegate void ActionClick();public static event ActionClick onClick;public void ButtonClick(){if(onClick != null){//change all coloronClick();}}// Start is called before the first frame update        }

现在我们给每个listener赋予一个脚本,所有独立的个体都会共享同一个脚本。The whole purpose of working with delegates in events is that it allows these cubes to be self contained. In this example, They don’t rely on the Main, they don’t rely on the button and they don’t rely on each other.
在这边我们给事件onClick方法赋值,把delegate所代表的方法添加到事件中,这个过程就叫做订阅。

 public class CubeForEvent : MonoBehaviour{// Start is called before the first frame updatevoid Start(){MainForEvent.onClick += ChangeColor;}// Update is called once per framepublic void ChangeColor(){this.GetComponent<Renderer>().material.color = new Color(Random.value, Random.value, Random.value);}}

就 整个的运行机制是什么呢?在这个例子中Main会对所有的cube进行一个foreach loop,然后过滤掉不属于代表的cube,剩余的进行改变颜色操作。但是我们cube之间是没有联系的,绑定Main脚本的Main Camera也没有获取cube的信息,都是独立开的。
场景应用很多,比如你的游戏中某个怪的生命值降到了30%以下,这个时候触发event,告知周围其他的怪。

  • WHY use events: events have inherit security while delegate variables do not. If we use the delegate variable, other classes could invoke and control the execution of your delegate. With events however, it only allows the classes to subscribe and unsubscribe from our delegate. It doesn’t allow us to actually invoke it. We can only do the subscribing and the unsubscribing. And u want to make sure that when u’re subscribing, u’re always unsubscribing somewhere, usually when u destory the obj. So we usually have this script for listener to avoid creating any type of error in your application.
     private void OnDisable() {MainForEvent.onClick -= ChangeColor;    }

emmm我们前面讲宗门例子时有提到我们的掌门可以发出多条命令,这些命令会分配给不同弟子比如身手敏捷的弟子埋伏暗杀啊修习炼体术的弟子负责当肉盾啊。同样的,在按钮和小方块的例子中,我们就再加一个小球吧,但是小球进行的操作不是变色而是掉落,那我们就可以对小球做这样一个脚本

 public class Sphere : MonoBehaviour{private void Start(){MainForEvent.onClick += LetItFall;}public void LetItFall(){this.GetComponent<Rigidbody>().useGravity = true;}}

Ok总结一下,event就是特殊情况下的deligate,是有触发场景条件的。以宗门的例子来说,宗门大比是一个event,宗门招新也是一个event,再不同event下,我们掌门会让弟子们做不同事情。有了event就能更好管理操作。下面的代码实现一个不同event的切换

/* Main */public class MainForEvent : MonoBehaviour{public delegate void ActionClick();public static event ActionClick onClick;public delegate void Move(int des);public static event Move toMove;public delegate void ChangePosition(Vector3 posi);public static event ChangePosition newPosi;public bool isDanger = true;// in different situation, invoke different event, and do different taskspublic void ButtonClick(){if(isDanger==true && onClick != null){//change all coloronClick();isDanger = false;}else if(isDanger==false && toMove != null){toMove(2);isDanger = true;}}private void Update(){if(Input.GetKeyDown(KeyCode.Space)){if(newPosi != null){newPosi(new Vector3(5,2,0));}}}}/* Cube */public class CubeForEvent : MonoBehaviour{// Start is called before the first frame updatevoid Start(){MainForEvent.onClick += ChangeColor;MainForEvent.toMove += ChangePosi;MainForEvent.newPosi += ChangePosi;}// Update is called once per framepublic void ChangeColor(){this.GetComponent<Renderer>().material.color = new Color(Random.value, Random.value, Random.value);}private void OnDisable() {MainForEvent.onClick -= ChangeColor;    }private void ChangePosi(int des){transform.position = transform.position + new Vector3(0, des, 0);}private void ChangePosi(Vector3 posi){transform.position = posi;}}

哦对 因为event是整个游戏过程中都可能会出发的,所以设置为静态变量。然后因为delegate有很严格的匹配,所以你的obj上的方法可以是多态的,它会自己匹配完全符合的那一个。应用场景的话,比如满血的event你的角色移动速度固定(无输入参数), 残血event时速度根据血量的百分比进行加速(输入参数为血量); 又或者是普攻的攻击力是多少多少(无输入参数),有buff加成的话攻击力多少多少(输入参数为buff对应), 不同buff加成方式也不一样,有的是按百分点(float),有的是直接一个整数(int),也有可能多个buff叠加(多参数),如果给每种都单独命名的话就很麻烦嘛(毕竟取名无能

(看到这边休息一下吧正好网卡了orz 啊好累 就三节我居然看了一天(窒息

OK继续

Actions

actions are identical to delegates and events, but instead of using two lines of code, one for delegate and one for the event, we can basically combine them into one line using actions.(作用是无差别的
下面是Action的一个例子 注释掉的部分是delegates+event的
需要注意的是,使用Action时要加上using System;才可以用

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace ChapterAction{public class PlayerForAction : MonoBehaviour{//public delegate void OnDamageReceived(int currHealth);//public static event OnDamageReceived onDamage;public static Action<int> OnDamageReceived;public int Health {get; set;}private void Start(){Health = 10;}void Damage(){Health --;/*if(onDamage != null){onDamage(Health);}*/if(OnDamageReceived != null){OnDamageReceived(Health);}}}
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace ChapterAction{public class UIManagerForAction : MonoBehaviour{       private void OnEnable(){//PlayerForAction.onDamage += UpdateHealth;PlayerForAction.OnDamageReceived += UpdateHealth;}// Start is called before the first frame updatepublic void UpdateHealth(int health){// displayed updated health hereDebug.Log("current health: "+health);}}
}

Return Type Delegates and Function

  • function delegate: return type delegate
    举个栗子,我们现在写一个小代码返回输入字符串长度。 之前的话都是这样子
     void Start(){int getlength = GetCharacters("WonWoo");Debug.Log(getlength);            }int GetCharacters(string name){return name.Length;}

那如果用基本的return type delegate呢(看下面) 要注意的一个是,因为这边delegate代表的方法是有返回值的,所以不能像前面代表void方法那样可以通过操作符+=来进行添加达到同时调用。

     public delegate int CharacterLength(string text);void Start(){CharacterLength getLength = new CharacterLength(GetCharacters); //orCharacterLength cl = GetCharacters;Debug.Log(cl("Joshua"));Debug.Log(getLength("wonwoo"));}  int GetCharacters(string name){return name.Length;}}

现在再来看看新同学function delegate。 和Action一样,我们要先导入System这个包。<>中是至少一个参数类型的声明,无论几个参数,最后一个都是TResult. 注意一下,因为Func也是一种特殊的delegate,所以传入参数类型不能多种(T),就只能一种,要嘛string要嘛int要嘛其他。

     public Func<string,int> CharacterLength;void Start(){CharacterLength = GetCharacters;Debug.Log(CharacterLength("Camus"));}

(我突然迷茫这样有什么用了感觉很鸡肋啊

C#: Lambda Expression

lambda expression allows us write methods in line
举个上一节的栗子 对就是下面这个 看看怎么改成lambda表达式

     public Func<string,int> CharacterLength;void Start(){CharacterLength = GetCharacters;Debug.Log(CharacterLength("Camus"));}int GetCharacters(string name){return name.Length;}

lambda操作符是=>表示goto,左边是传入参数,右边是返回值或者函数体(如果是函数体的话要用{}括起来
(怎么那么像js啊

     public Func<string,int> CharacterLength;void Start(){CharacterLength = (name) => name.Length; //lambda expDebug.Log(CharacterLength("Camus"));}

Practice

  1. Practice Delegate of Type void with Paramters
 public class PracticeDelegateOne : MonoBehaviour{/* Practice// create a delegate of type void that calculates the sum of two num.// use a lambda to avoid dedicated method*/public delegate void CalculateSum(int a, int b); public CalculateSum calculateSum;// Start is called before the first frame updatevoid Start(){calculateSum = (a, b) => Debug.Log(a+b);calculateSum(3, 6);}}
  1. Practice Delegate of Type void with No Paramters using lambda
    (用了普通的return void delegate和Action这两种
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;namespace ChapterDelegate{public class PracticeDelegateThree : MonoBehaviour{/* Practice// create a delegate of type int that returns the length of gameobj name// without param*/// using ori delegatepublic delegate int LengthOfName();public LengthOfName lengthOfName;// using func delegatepublic Func<int> GetLength;// Start is called before the first frame updatevoid Start(){lengthOfName = () => this.name.Length;Debug.Log(lengthOfName());GetLength = () => this.name.Length;Debug.Log(GetLength());}}
}
  1. Practice Delegate of Return Type without Paramters
    用delegate和func两种
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;namespace ChapterDelegate{public class PracticeDelegateThree : MonoBehaviour{/* Practice// create a delegate of type int that returns the length of gameobj name// without param*/// using ori delegatepublic delegate int LengthOfName();public LengthOfName lengthOfName;// using func delegatepublic Func<int> GetLength;// Start is called before the first frame updatevoid Start(){lengthOfName = () => this.name.Length;Debug.Log(lengthOfName());GetLength = () => this.name.Length;Debug.Log(GetLength());}}
}
  1. Practice Delegate of Return Type with Paramters
    直接用Func了…懒得用普通delegate
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;namespace ChapterDelegate{public class PracticeDelegateFour : MonoBehaviour{/* Practice// create a delegate of type int that takes two param and add the sum*/public Func<int, int, int> AddSum;// Start is called before the first frame updatevoid Start(){AddSum = (x, y) => x+y;Debug.Log(AddSum(1, 1));}}
}

Simple Callback System

顺便回忆一下协程

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;public class CallbackSys : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){StartCoroutine(MyRoutine(()=>{Debug.Log("the routine complete");Debug.Log("surprise!");}));}public IEnumerator MyRoutine(Action onComplete = null){yield return new WaitForSeconds(5.0f); //after game start 5sif(onComplete != null){onComplete();}}
}

[U3D Learning Note] Unity C# Survival Guide (17) --Delegates and Events相关推荐

  1. 3D Modeling for Unity: The Complete Guide

    3D Modeling for Unity: The Complete Guide Software for 3D Modeling for Unity There are 3 major tools ...

  2. 代码外的任务很精彩 ---Software project survival guide 读书报告

    Software project survival guide (软件项目生存指南) 是我在MSRA软件工程课程期间选读的书.书名起得很朴素,我们可以猜测到作者会讲些什么,以什么方式描述.它不像< ...

  3. 2014/09/30 Learning Note

    Vbird Linux: Vim Learning: http://linux.vbird.org/linux_basic/0310vi.php Bash Shell: http://linux.vb ...

  4. Python 基础 - Day 5 Learning Note - 模块 之 标准库:xml (9)

    xml 模块介绍 和json一样,适用于不同语言及程序的数据交换的协议.但是json用起来更简单,并有代替xml的趋势. 现在多数金融数据提供方(e.g. bloombegy)还在用xml的方式. 在 ...

  5. LUA Learning Note 4: 数据结构

    为什么80%的码农都做不了架构师?>>>    --数据结构是没有语言之分的,只不过不同的语言实现起来的语法不同. --创建一个简单的数组 local arr1 = {1,2,3,4 ...

  6. Python 基础 - Day 2 Learning Note - 序列之字符串 String

    字符串(string)特点: 不可修改 独立的字符组成, 通过slice切片操作顺序访问 创建 '' or "" or str() aString = 'alex Chai' # ...

  7. Python 基础 - Day 2 Learning Note - 字符转编码操作

    前情提要:字符编码 python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill).ASCILL有255个字符,包括英语和西欧字符,不包括中文.汉字处理靠GBK, window ...

  8. Spring Learning Note

    1.Introduction of Spring purpose:解决企业级开发的复杂性,整合了现有技术框架 SSH:Struct2+Spring+Hibernate 旧三大框架:SSH Struts ...

  9. Unity的C#编程教程_61_委托和事件 Delegates and Events 详解及应用练习

    文章目录 C# Delegates C# Events Example Working with C# Delegates and Events Challenge: Teleport Events ...

最新文章

  1. c语言double变量后面几个0,C语言double型变量的初始化到底是是0还是0.0?
  2. 解决XP系统启动慢的问题
  3. mysql limit不要1_切记!MySQL中ORDER BY与LIMIT 不要一起用,有大坑
  4. 老司机也晕车--java字符串String晕车之旅
  5. 在本机上安装zabbix,来监控服务器 六
  6. html标签anchor,浏览器端-W3School-HTML:HTML DOM Anchor 对象
  7. UNION 和UNION ALL的区别
  8. Wtm携手LayUI -- .netcore 开源生态我们是认真的!
  9. 职涯成长的认知与突破
  10. Deep Learning for Joint Channel Estimation and Feedback in Massive MIMO Systems
  11. ArcGIS Server 发布 REST 服务
  12. PHP腾讯云短信接口
  13. 操作系统内存及内存管理方式
  14. C语言基础入门:C-Free5设置支持C99标准
  15. python 空数组_Python笔记
  16. css3动画: 3d照片旋转transfrom
  17. SaaS是Software-as-a-Service(软件即服务)
  18. itest软件测试工具,Monkey测试工具 - iTest99的个人空间 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  19. 公众号配置服务器信息在哪里,公众号服务器配置在哪
  20. Stereo Parallel Tracking and Mapping for robot localization(S-PTAM)

热门文章

  1. 3dslicer打开.vtk文件失败
  2. MongoDB 数据操作(四)数据删除
  3. React Native API之—— Keyboard键盘相关
  4. Android-传感器-计步
  5. Adobe Acrobat DC 打开上次浏览的PDF及位置
  6. 计算机二级考试2021考试时间黑龙江,黑龙江2021上半年计算机应用水平考试报名时间 哪天报名...
  7. 零基础入门原画必知的技巧
  8. 类和对象(中)——构造函数介绍
  9. 全面解读流程图|附摩拜ofo案例分析(附内推)
  10. [转]md语法|LaTex数学公式