【Unity项目实践】事件进阶
  EFTJ6596AiAP 2023年11月02日 74 0

以下内容为学习刘铁猛老师课程的课程笔记。

事件声明

声明一个自定义事件。

事件是基于委托的:

事件需要委托来做约束,事件处理器需要和约束对应上;

事件处理器需要保存和记录,只有委托类型的实例可以做到。


委托是事件的基础,事件是委托的上层建筑。


委托是一个类,声明一个委托类型和声明一个委托类型的字段是不一样的。

事件的触发一定是事件拥有者的一些内部逻辑触发的事件。


以下代码展示了事件的完整声明:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace ComputingWithCSharp
{
public class Program
{
static void Main(string[] args)
{
Customer customer = new Customer();
Waiter waiter = new Waiter();
customer.Order += waiter.Action;//事件订阅
customer.Action();
customer.PayTheBill();
}
}

public class OrderEventArgs: EventArgs //传递的事件消息
{
public string dishName { get; set; }
public string size { get; set; }
}

//声明一个委托,委托是一个类
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
//表明这个委托用来约束事件处理器;用来存放事件处理器
//如果在Customer类中声明,就成为了一个嵌套的类

public class Customer//拥有者
{
private OrderEventHandler orderEventHandler;

public event OrderEventHandler Order//事件
{
add
{
this.orderEventHandler += value;
}

remove
{
this.orderEventHandler -= value;
}
}

public double Bill { get; set; }
public void PayTheBill()
{
Console.WriteLine("I will pay ${0}.", this.Bill);
}


public void WalkIn()
{
Console.WriteLine("Walk into the restaurant");
}

public void SitDown()
{
Console.WriteLine("Sit Down");
}

public void Think()
{
for (int i=0; i<5; i++)
{
Console.WriteLine("Let me think");
Thread.Sleep(1000);
}

if (this.orderEventHandler != null)
{
OrderEventArgs e = new OrderEventArgs();
e.dishName = "chicken";
e.size = "large";
this.orderEventHandler.Invoke(this, e);
}
}

public void Action()
{
Console.ReadLine();
this.WalkIn();
this.SitDown();
this.Think();
}
}


public class Waiter//事件响应者
{
public void Action(Customer customer, OrderEventArgs e)//事件处理器
{
Console.WriteLine("I will serve you the dish-{0}.", e.dishName);
double price = 10;
switch (e.size)
{
case "small":
price = price * 0.5;
break;
case "large":
price = price * 1.5;
break;
default:
break;
}

customer.Bill += price;
}
}
}


事件声明的简单形式:

field-like

public event OrderEventHandler Order;//事件的简单声明,很像一个字段的声明,但实质上不是
public OrderEventHandler Order;//这实际上就是声明了一个字段

为什么需要事件:程序更加有逻辑。

Customer customer = new Customer();
Waiter waiter = new Waiter();
customer.Order += waiter.Action;

OrderEventArgs e = new OrderEventArgs();
e.dishName = "Manhanquanxi";
e.size = "large";

OrderEventArgs e2 = new OrderEventArgs();
e2.dishName = "Beer";
e2.size = "large";

Customer badGuy = new Customer();
badGuy.Order += waiter.Action;
badGuy.Order.Invoke(customer, e);
badGuy.Order.Invoke(customer, e2);
customer.PayTheBill();

不使用委托的话,没有对某个方法进行限制,所以一个顾客可以调用别的顾客的方法。


事件的本质是委托字段的一个包装器,对委托字段的访问起限制作用,类似于蒙版。

事件对外界隐藏了委托实例的大部分功能,仅展示了添加/移除事件处理器的功能。


事件的命名

一般用On开头加上事件名的方式来触发事件

public void Think()
{
for (int i=0; i<5; i++)
{
Console.WriteLine("Let me think");
Thread.Sleep(1000);

}
OnOrder("chicken", "large");

}


protected void OnOrder(string dishName, string size)//需要是protected,保证不能被外界访问
{
if (this.Order != null)//判断事件封装的委托是否为空
{
OrderEventArgs e = new OrderEventArgs();
e.dishName = dishName;
e.size = size;
this.Order.Invoke(this, e);//事件只能用在订阅和取消订阅符号的左边,这里不可以用事件
}
}


命名约定:

  • 使用动词
  • 正在做用进行时,做完了用完成时


一些误解

事件 & 委托

事件声明的时候使用了委托类型,尤其是简化的声明方式很像在声明字段;

订阅的时候用到了委托类型的实例;


完整声明中事件是不可以判断是否为空的,也不可以用来调用。


事件基于委托:

source:表明source能对外传递哪些信息;

subscriber:是一种约定,为了约束能够用什么签名来处理事件;

委托类型的实例将用于存储/引用事件处理器。



事件和属性有相似之处:

属性是字段的包装器,防止字段被滥用

事件是委托字段的包装器,防止委托字段被滥用





【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

EFTJ6596AiAP