image.pngimage.png
事件是不是委托类型的字段?是不是一个特殊类型的委托类型的字段?
简略声明格式“确实像”一个字段;事件并不是一个字段;

反编译器中查看:
<蓝色箭头:事件 菱形:字段)>
①属性(Bill)简略声明的时候,为我们准备的后台字段
②第二条:编译器,为我们简化的事件声明方式,准备了那个委托类型的字段。

其实我们委托类型的字段,虽然没有手动声明在脚本中,但其实它只是没有出现在我们的代码当中。实际上出现在了后台当中。为我们将来储存事件处理器的。

1650764989(1).png

继续优化

事件平台当中,我们可以去使用一种非常通用的委托:EventHandler委托。

因为OrderEventArgs是EventArgs所派生出来的(是EventArgs的子类)。委托类型从OrderEventHandler变成EventArgs,势必约定已经打破了,改变了。对应的事件处理器也一定会发生改变。原本的事件处理器的参数列表,将不会符合要求。
image.png①as

完整代码

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System;
  5. //事件模型的 [五个组成部分]
  6. //事件的拥有者【类】------>Customer类
  7. //事件【event关键字修饰】------>OnOrder点餐事件
  8. //事件的响应者【类】------>Waiter类
  9. //事件处理器【方法 - 受到约束的方法】------>TakeAction方法
  10. //事件的订阅关系【+=】------>+=
  11. public delegate void OrderEventHandler(Customer _customer, OrderEventArg _e);
  12. public class EventEx1 : MonoBehaviour
  13. {
  14. Customer customer = new Customer();
  15. Waiter waiter = new Waiter();
  16. private void Start()
  17. {
  18. customer.OnOrder += waiter.TakeAction;//需要与委托类型保持一致
  19. customer.Order("Mocha","Grand",32);//事件拥有者的内部逻辑,触发的事件
  20. customer.Order("Makalong", "Tall", 16);
  21. customer.PayTheBill();
  22. }
  23. }
  24. public class Customer
  25. {
  26. public float Bill { get; set; }
  27. public void PayTheBill()
  28. {
  29. Debug.Log("Pay:" + "$" + this.Bill);
  30. }
  31. public event EventHandler OnOrder;
  32. public void Order(string _name,string _size,float _price)
  33. {
  34. if(OnOrder != null)//判断事件是否为空,语法糖
  35. {
  36. OrderEventArg e = new OrderEventArg();
  37. e.CoffeeName = _name;
  38. e.CoffeeSize = _size;
  39. e.CoffeePrice = _price;
  40. OnOrder(this, e);
  41. }
  42. }
  43. }
  44. //创建一个用来传递事件参数(事件信息、消息)属于EventArgs这个类,即名字:事件名 + EventArgs作为后缀
  45. //派生自EventArgs这个类型,也是微软、厂商为我们准备好的一个基类
  46. public class OrderEventArg : EventArgs
  47. {
  48. public string CoffeeName { get; set; }
  49. public string CoffeeSize { get; set; }
  50. public float CoffeePrice { get; set; }
  51. }
  52. public class Waiter
  53. {
  54. internal void TakeAction(object _sender, EventArgs _ea)
  55. {
  56. float finalPrice = 0;
  57. Customer customer = _sender as Customer;
  58. OrderEventArg e = _ea as OrderEventArg;
  59. switch (e.CoffeeSize)
  60. {
  61. case "Tall":
  62. finalPrice = e.CoffeePrice;//中杯:原价
  63. break;
  64. case "Grand":
  65. finalPrice = e.CoffeePrice + 3;//大杯:原价+3
  66. break;
  67. case "Venti":
  68. finalPrice = e.CoffeePrice + 6;//超大杯:原价+6
  69. break;
  70. }
  71. customer.Bill += finalPrice;
  72. }
  73. }

分析错误

image.png
错误示范①:简略声明格式下,尝试抹去event。此时程序正常运作,不报错,输出正确的结果。此时发现,该委托类型的字段为public,谁都可以访问它的。它就会隐藏一些潜在的问题,—->借刀杀人

面试官提问一:委托和事件的关系?
image.png

不是委托类型字段,只是委托类型字段的包装器、限制器,限制外界对委托类型字段的访问。
委托类型的字段经过事件这么一包装、限制之后,外界只能去访问他的+=(添加)、-=(移除)操作符 事件处理器。
面试官提问二:为什么要使用委托类型来声明事件?(为什么事件是基于委托的?)