14.委托和事件-事件
14.1 知识点
事件是什么
事件是基于委托的存在,是委托的安全包裹,让委托的使用更具有安全性。事件是一种特殊的变量类型。
事件的使用
事件的基础知识
申明语法:
访问修饰符 event 委托类型 事件名;
事件的使用:
- 事件是作为成员变量存在于类中。
- 委托怎么用,事件就怎么用。
事件相对于委托的区别:
- 不能在类外部赋值。
- 不能再类外部调用。
注意:它只能作为成员存在于类和接口以及结构体中。
class语句块外 namespace语句块内
测试事件类:
class TestEvent
{
// 委托成员变量,用于存储函数的无参数无返回值
public Action myAction;
// 事件成员变量,用于存储函数的无参数无返回值
public event Action myEvent;
// 测试事件类构造函数
public TestEvent()
{
// 事件的使用和委托一模一样,只是有些细微的区别
// 委托怎么用,事件就怎么用
myAction = Print123;
myAction += Print123;
myAction -= Print123;
myAction();
myAction.Invoke();
myEvent = Print123;
myEvent += Print123;
myEvent -= Print123;
myEvent();
myEvent.Invoke();
}
// 封装的方法,执行事件
public void DoEvent()
{
// 事件不为空的话,执行事件
if (myEvent != null)
{
myEvent();
}
}
// 打印123函数
public void Print123()
{
Console.WriteLine("123");
}
}
class语句块内 主函数外
打印456函数:
static void Print456()
{
Console.WriteLine("456");
}
主函数内
// 创建测试事件类
TestEvent testEvent = new TestEvent();
// 委托可以在外部赋值
testEvent.myAction = null;
testEvent.myAction = Print456;
testEvent.myAction = testEvent.myAction + Print456;
testEvent.myAction += Print456;
// 事件是不能再外部赋值的,否则报错
// testEvent.myEvent = null;//报错
// testEvent.myEvent = Print123;//报错
// 事件虽然不能直接赋值,但是可以加减去添加移除记录的函数
testEvent.myEvent += Print456;
// testEvent.myEvent = testEvent.myEvent + Print456;//报错,事件不支持这样写
testEvent.myEvent -= Print456;
// 委托是可以在外部调用的
testEvent.myAction();
testEvent.myAction.Invoke();
// 事件不能再外部调用
// testEvent.myEvent();//报错
// testEvent.myEvent.Invoke();//报错
// 只能在类的内部去封装调用
testEvent.DoEvent();
// 委托能作为临时变量在函数中使用
Action a = Print456;
// 事件是不能作为临时变量在函数中使用的
// event Action eA = Print456;//报错
为什么有事件
- 防止外部随意置空委托。
- 防止外部随意调用委托。
- 事件相当于对委托进行了一次封装,让其更加安全。
总结
事件和委托的区别:
- 事件和委托的使用基本是一模一样的。
- 事件就是特殊的委托。
主要区别:
- 事件不能再外部使用赋值=符号,只能使用+ -。委托哪里都能用。
- 事件不能再外部执行,委托哪里都能执行。
- 事件不能作为函数中的临时变量,委托可以。
14.2 知识点代码
using System;
namespace Lesson13_事件
{
#region 知识点一 事件是什么
//事件是基于委托的存在
//事件是委托的安全包裹
//让委托的使用更具有安全性
//事件 是一种特殊的变量类型
#endregion
//class语句块外 namespace语句块内
#region 知识点二 事件的使用
//事件的基础知识
//申明语法:访问修饰符 event 委托类型 事件名;
//事件的使用:
//1.事件是作为 成员变量存在于类中
//2.委托怎么用 事件就怎么用
//事件相对于委托的区别:
//1.不能在类外部 赋值
//2.不能再类外部 调用
//注意:它只能作为成员存在于类和接口以及结构体中
//测试事件类
class TestEvent
{
//委托成员变量 用于存储 函数的 无参数无返回值
public Action myAction;
//事件成员变量 用于存储 函数的 无参数无返回值
public event Action myEvent;
//测试事件类构造函数
public TestEvent()
{
//事件的使用和委托 一模一样 只是有些 细微的区别
//委托怎么用 事件就怎么用
myAction = Print123;
myAction += Print123;
myAction -= Print123;
myAction();//123
myAction.Invoke();//123
myAction = null;
myEvent = Print123;
myEvent += Print123;
myEvent -= Print123;
myEvent();//123
myEvent.Invoke();//123
myEvent = null;
}
//封装的方法 执行事件
public void DoEvent()
{
//事件不为空的话 执行事件
if (myEvent != null)
{
myEvent();
}
}
//打印123函数
public void Print123()
{
Console.WriteLine("123");
}
}
#endregion
#region 知识点三 为什么有事件
//1.防止外部随意置空委托
//2.防止外部随意调用委托
//3.事件相当于对委托进行了一次封装 让其更加安全
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("事件");
//主函数内
#region 知识点二 事件的使用
//创建测试事件类
TestEvent testEvent = new TestEvent();
//委托可以在外部赋值
testEvent.myAction = null;
testEvent.myAction = Print456;
testEvent.myAction = testEvent.myAction + Print456;
testEvent.myAction += Print456;
//事件是不能再外部赋值的 否则报错
//testEvent.myEvent = null;//报错
//testEvent.myEvent = Print123;//报错
//事件虽然不能直接赋值 但是可以 加减 去添加移除记录的函数
testEvent.myEvent += Print456;
//testEvent.myEvent = testEvent.myEvent + Print456;//报错 事件不支持这样写
testEvent.myEvent -= Print456;
//委托是可以在外部调用的
testEvent.myAction();
testEvent.myAction.Invoke();
//事件不能再外部调用
//testEvent.myEvent();//报错
//testEvent.myEvent.Invoke();//报错
//只能在类的内部去封装 调用
testEvent.DoEvent();
//委托 能作为临时变量在函数中使用的
Action a = Print456;
//事件 是不能作为临时变量在函数中使用的
//event Action eA = Print456;//报错
#endregion
}
//class语句块内 主函数外
#region 知识点二 事件的使用
//打印456函数
static void Print456()
{
Console.WriteLine("456");
}
#endregion
}
//总结
//事件和委托的区别
//事件和委托的使用基本是一模一样的
//事件就是特殊的委托
//主要区别:
//1.事件不能再外部使用赋值=符号,只能使用+ - 委托 哪里都能用
//2.事件 不能再外部执行 委托哪里都能执行
//3.事件 不能作为 函数中的临时变量的 委托可以
}
14.3 练习题
有一个热水器,包含一个加热器,一个报警器,一个显示器,我们给热水器通上电,当水温超过95度时,报警器会开始发出语音,告诉你谁的温度,显示器也会改变水温提示,提示水已经烧开了
class语句块外 namespace语句块内
// 加热器
class Heater
{
// 加热到95度是加热器执行的事件
public event Action<int> heaterEvnet;
// 当前摄氏度
private int celsius = 0;
// 加热方法
public void AddHot()
{
// 帧数计数
int updateIndex = 0;
while (true)
{
// 每9999999帧进一次循环
if (updateIndex % 9999999 == 0)
{
++celsius;
Console.WriteLine("加热到{0}摄氏度", celsius);
// 为了不频繁打印 超过100度 直接 不加热 测试用
if (celsius >= 100)
{
break;
}
// 温度超过95度 就触发 报警器和显示器显示信息
if (celsius >= 95)
{
// 加热器事件不为空就执行
heaterEvnet?.Invoke(celsius);
// 如果只想提示一次 这清空事件容器即可
heaterEvnet = null;
}
// 隔一段时间 加一点温度
updateIndex = 0;
}
// 增加帧数
++updateIndex;
}
}
}
// 报警器
class Alarm
{
public void ShowInfo(int celsius)
{
Console.WriteLine("警报!当前水温是{0}摄氏度!", celsius);
}
}
// 显示器
class Display
{
public void ShowInfo(int celsius)
{
Console.WriteLine("水开了,当前显示的水温是{0}摄氏度", celsius);
}
}
主函数内
// 创建一个加热器,一个报警器,一个显示器
Heater heater = new Heater();
Alarm alarm = new Alarm();
Display display = new Display();
// 报警器和显示器要做的事情加到加热器事件里
heater.heaterEvnet += alarm.ShowInfo;
heater.heaterEvnet += display.ShowInfo;
// 加热器加热
heater.AddHot();
// 加热到1摄氏度
// 加热到2摄氏度
// 加热到3摄氏度
// ...
// 加热到94摄氏度
// 加热到95摄氏度
// 警报!当前水温是95摄氏度!
// 水开了,当前显示的水温是95摄氏度
// 加热到96摄氏度
// 加热到97摄氏度
// 加热到98摄氏度
// 加热到99摄氏度
// 加热到100摄氏度
14.4 练习题代码
using System;
namespace Lesson13_练习题
{
//class语句块外 namespace语句块内
#region 练习题一
//有一个热水器,包含一个加热器,一个报警器,一个显示器
//我们给热水器通上电,当水温超过95度时
//1.报警器会开始发出语音,告诉你水的温度
//2.显示器也会改变水温提示,提示水已经烧开了
//加热器
class Heater
{
//加热到95度是加热器执行的事件
public event Action<int> heaterEvnet;
//当前摄氏度
private int celsius = 0;
//加热方法
public void AddHot()
{
//帧数计数
int updateIndex = 0;
while (true)
{
//每9999999帧进一次循环
if (updateIndex % 9999999 == 0)
{
++celsius;
Console.WriteLine("加热到{0}摄氏度", celsius);
//为了不频繁打印 超过100度 直接 不加热 测试用
if (celsius >= 100)
{
break;
}
//温度超过95度 就触发 报警器和显示器显示信息
if (celsius >= 95)
{
//加热器事件不为空就执行
if (heaterEvnet != null)
{
heaterEvnet(celsius);
}
//如果只想提示一次 这清空事件容器即可
heaterEvnet = null;
}
//隔一段时间 加一点温度
updateIndex = 0;
}
//增加帧数
++updateIndex;
}
}
}
//报警器
class Alarm
{
public void ShowInfo(int celsius)
{
Console.WriteLine("警报!当前水温是{0}摄氏度!", celsius);
}
}
//显示器
class Display
{
public void ShowInfo(int celsius)
{
Console.WriteLine("水开了,当前显示的水温是{0}摄氏度", celsius);
}
}
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("事件练习题");
//主函数内
#region 练习题一
//创建一个加热器,一个报警器,一个显示器
Heater heater = new Heater();
Alarm alarm = new Alarm();
Display display = new Display();
//报警器和显示器要做的事情加到加热器事件里
heater.heaterEvnet += alarm.ShowInfo;
heater.heaterEvnet += display.ShowInfo;
//加热器加热
heater.AddHot();
//加热到1摄氏度
//加热到2摄氏度
//加热到3摄氏度
//...
//加热到94摄氏度
//加热到95摄氏度
//警报!当前水温是95摄氏度!
//水开了,当前显示的水温是95摄氏度
//加热到96摄氏度
//加热到97摄氏度
//加热到98摄氏度
//加热到99摄氏度
//加热到100摄氏度
#endregion
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com