C#事件(event)的理解
一、多播委托的应用--观察者模式
遇到一个开发的问题?
面试者:以面向对象的思想实现一下的场景:
猫:Miao一声,紧接着引发了一系列的行为~
Miao:引发了一系列的动作;
从代码层面来说:代码这样写好吗?
- 猫职责不单一(猫就是猫,他的行为只有Miao一声)
- 依赖太重,依赖了很多的普通类; 被依赖的类如果修改,可能会引发这个猫也要修改;---代码不稳定;
- 如果要控制顺序---也要修改代码; 有新需求,必须要修改历史代码---开闭原则;
从传统的方式去考虑的话,我们可能会写出来这个如此这样的代码
class Dog
{
public void Bark()
{
Console.WriteLine("Dog Bark!");
}
}
class Fox
{
public void Eat()
{
Console.WriteLine("Fox Eat!");
}
}
class Cat
{
public void Miao()
{
new Fox().Eat();
new Dog().Bark();
Console.WriteLine("Cat Miao!");
}
}
从代码层面来说:代码这样写好吗?
- 猫职责不单一(猫就是猫,他的行为只有Miao一声)
- 依赖太重,依赖了很多的普通类; 被依赖的类如果修改,可能会引发这个猫也要修改;---代码不稳定;
- 如果要控制顺序---也要修改代码; 有新需求,必须要修改历史代码---开闭原则;
如何解决呢? 第一个问题:让猫的职责单一, 后续触发的行为,猫Miao一声之后,只负责触发; 触发的是一堆的行为;
请问:如果要希望在触发一个行为后,能够执行多个行为,执行一系列的行为?? 怎么办?-------多播委托;
核心:把依赖的东西转移到上端,保证当前类的稳定; ----可以做到解耦
二者实现本质:是相通的; 都是类似于一个盒子, OOP: 盒子中装对象 委托:盒子装方法;
通过OOP 继承实现的ObServer
IObject.cs
public interface IObject
{
public void DoAction();
}
Baby.cs
public class Baby:IObject
{
public void Cry()
{
Console.WriteLine("Baby Cry");
}
public void DoAction()
{
Cry();
}
}
Brother.cs
public class Brother:IObject
{
public void Turn()
{
Console.WriteLine("Brother Turn");
}
public void DoAction()
{
Turn();
}
}
Dog.cs
public class Dog:IObject
{
public void Wang()
{
Console.WriteLine("Dog Wang");
}
public void DoAction()
{
Wang();
}
}
Father.cs
public class Father:IObject
{
public void Roar()
{
Console.WriteLine("Father Roar");
}
public void DoAction()
{
Roar();
}
}
Mother.cs
public class Mother:IObject
{
public void Wispher()
{
Console.WriteLine("Mother Wispher");
}
public void DoAction()
{
Wispher();
}
}
Mouse.cs
public class Mouse:IObject
{
public void Run()
{
Console.WriteLine("Mouse Run");
}
public void DoAction()
{
Run();
}
}
Neighbor.cs
public class Neighbor:IObject
{
public void Awake()
{
Console.WriteLine("Neighbor Awake");
}
public void DoAction()
{
Awake();
}
}
Stealer.cs
public class Stealer:IObject
{
public void Hide()
{
Console.WriteLine("Stealer Hide");
}
public void DoAction()
{
Hide();
}
}
Cat.cs
public class Cat
{
public List<IObject> ObserList=new List<IObject>();
public void MiaoObserver()
{
Console.WriteLine($"{this.GetType().Name} MiaoObserver========");
foreach ( IObject item in ObserList )
{
item.DoAction();
}
}
}
Progarm.cs
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
{
Cat cat = new Cat();
cat.objects.Add(new Baby());
cat.objects.Add(new Mother());
cat.objects.Add(new Dog());
cat.objects.Add(new Mouse());
cat.objects.Add(new Father());
cat.objects.Add(new Neighbor());
cat.objects.Add(new Stealer());
cat.objects.Add(new Brother());
cat.MiaoObserver();
}
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
通过委托实现
cat.cs
public Action? MiaoDelegate;
public void MiaoDelegateObserver()
{
Console.WriteLine($"{this.GetType().Name} MiaoDelegateObserver========");
if (MiaoDelegate != null)
{
MiaoDelegate();
}
}
program.cs
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
{
Cat cat = new Cat();
cat.MiaoDelegate += new Baby().Cry;
cat.MiaoDelegate += new Mother().Wispher;
cat.MiaoDelegate += new Dog().Wang;
cat.MiaoDelegate += new Mouse().Run;
cat.MiaoDelegate += new Father().Roar;
cat.MiaoDelegate += new Neighbor().Awake;
cat.MiaoDelegate += new Stealer().Hide;
cat.MiaoDelegate += new Brother().Turn;
//cat.ActionHander -= new Baby().Cry;
// cat.ActionHander.Invoke();// 委托可以在定义委托所在类的外部去执行;
cat.MiaoDelegateObserver();
}
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
通过事件实现
cat.cs
public event Action ActionHanderEvent;
public void MiaoEvent()
{
Console.WriteLine($"{this.GetType().Name} MiaoEvent========");
ActionHanderEvent.Invoke(); //这个行为要一定是执行 MiaoEvent方法的时候才触发的;
}
program.cs
Console.WriteLine("事件的应用:============================");
{
Cat cat = new Cat();
cat.ActionHanderEvent += new Baby().Cry;
cat.ActionHanderEvent += new Mother().Wispher;
cat.ActionHanderEvent += new Dog().Wang;
cat.ActionHanderEvent += new Mouse().Run;
cat.ActionHanderEvent += new Father().Roar;
cat.ActionHanderEvent += new Neighbor().Awake;
cat.ActionHanderEvent += new Stealer().Hide;
// cat.ActionHanderEvent -= new Baby().Cry;
//cat.ActionHanderEvent.Invoke();
cat.MiaoEvent ();
}
什么是事件,其实就是委托的实例+关键字; 事件是一个特殊的委托;
委托和事件有什么区别?
1 多个了关键字
2 事件的权限控制会更加严格--事件的执行,只能,必须在声明这个事件所在的类的内部才能执行;
已经有了委托,为什么还要事件呢?----在系统框架设计中,需要这样的权限控制;
已经有了委托,为什么还要事件呢?----在系统框架设计中,需要这样的权限控制;
使用winform程序来做示范

登录
思路:按钮点击会触发这个方法,如果是通过事件来完成,必然会有一个地方定义得有事件,还要把这个方法给注册到事件中去;
执行的逻辑:在按钮初始化的时候,把按钮中的Click 指向一个方法btnLogin_Click;
运行起来: 鼠标点击按钮----操作系统可以捕捉到鼠标的信号,通过句柄判断,确定是哪个程序,通过程序中句柄判断是按个一个组件(按钮),可以获取到按钮的实例; 得到的是登录按钮; 鼠标单机左键信号,按钮
委托和事件的功能差不多---按钮的点击后触发的行为,为什么用事件而不用委托?????
就是为了要管控这个按钮,只能在特定的情况下去执行;
如果用委托:委托就可以在外部去执行;
点击登录,触发登录的方法----必须是点击登录后触发 所以只能用事件而不能用委托
点击注册,触发注册的方法----必须是点击注册后触发 所以只能用事件而不能用委托
不能通过任何其他别的渠道来触发这个方法
如果我使用委托:尽管一在点击了按钮之后,可以触发对应的行为,但是委托没有权限的限制,就可以在外部执行这个委托----不允许的;保证动作触发的来源一定是来自于哪里;
委托和事件的相通性:
二者功能差不多,观察者;在程序中,除了保证代码的问题;
其他场景
三个按钮---鼠标指向---变颜色(按钮的行为); 所有的按钮都有这个行为; 而单单只有登录和注册--点击后可以触发对应的方法;因为给这两个按钮的Click事件注册了行为;
在系统的框架中,如果有一段逻辑的执行; 其中有一些通用的逻辑(三个按钮都有执向变颜色),还有一些个性化的逻辑,每个按钮点击后可能需要执行不同的逻辑; 可以通过事件来进行注册;
价值: 可以把通用的逻辑封装
把可变的逻辑通过事件注册
执行来了,通用逻辑(统一的代码执行)-----可变的逻辑(各自执行各自的~·) 程序可以更加灵活~~ Web--- ASP.NET MVC管道处理模型~~
2.定义事件+实现发布订阅
1.朝夕要发布新课程,嵌入式和C++ Qt (都是Richard老师给大家上课)
2.很多小伙伴们很期待,很关注
3.如果课程发布,根据需求报名学习
public class EventStandard
{
private static PublicCourse publicCourse1 = new PublicCourse()
{
Id = 222,
Name = "Qt和C++",
};
private static PublicCourse publicCourse2 = new PublicCourse()
{
Id = 222,
Name = "嵌入式开发",
};
/// <summary>
/// 发布课程
/// </summary>
public static void Show()
{
publicCourse1.PublicShow();// 只关注发布,发布后,会有后续的行为
publicCourse2.PublicShow();
}
/// <summary>
/// 初始化订阅者和发布者之间的关系( 订阅中心 )
/// </summary>
public static void Init()
{
StudentUser user1 = new StudentUser()
{
Id = 123,
Name = "夕林吹雪"
};
publicCourse1.Publish += user1.Buy;
publicCourse2.Publish += user1.Buy;
StudentUser user2 = new StudentUser()
{
Id = 123,
Name = "张三"
};
publicCourse1.Publish += user2.Buy;
publicCourse2.Publish += user2.Buy;
StudentUser user3 = new StudentUser()
{
Id = 123,
Name = "李四"
};
publicCourse1.Publish += user3.Buy;
publicCourse2.Publish += user3.Buy;
}
}
/// <summary>
/// 发布者
/// 发布后,就会有后续的逻辑---具体是什么,不知道
/// </summary>
public class PublicCourse
{
public int Id { get; set; }
public string Name { get; set; }
public void PublicShow()
{
Console.WriteLine("朝夕新课程发布: Qt+C++ 嵌入式开发~~~");
//会有很多的人关注
//会有很多的后续动作执行, 有人咨询,有人报名,有人体验课程~
Publish.Invoke(this, new CourseInfo()
{
Id=345,
Title="Qt和 C++"
});
}
public event EventHandler Publish;
}
/// <summary>
/// 订阅者(订户):
/// 订阅消息,消息出现,就会触发行为;
/// </summary>
public class StudentUser
{
public int Id { get; set; }
public string Name { get; set; }
public void Buy(object? sender, EventArgs e)
{
PublicCourse course= (PublicCourse)(sender);
Console.WriteLine($"朝夕有新的课程发布,可称为{course.Name}");
Console.WriteLine($"用户:{Name}先了解下,考虑考虑");
Console.WriteLine($"可以购买学习~~");
}
}
/// <summary>
/// 扩展参数
/// </summary>
public class CourseInfo : EventArgs
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string TeacherWechatNum { get; set; }
}
C#事件(event)的理解的更多相关文章
- 深入理解事件(Event)
前言 在前一篇文章中讲到了Event 发布与订阅(一) 里面用到了事件来实现一些发布与订阅,当时对事件及其委托理解的还不是太深入,可能在使用上有点捉急.这篇来好好讲讲事件,以及通过一些小DEMO来加深 ...
- C#事件(event)解析
事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于window ...
- C#中的委托(Delegate)和事件(Event)
原文地址:C#中的委托(Delegate)和事件(Event) 作者:jiyuan51 把C#中的委托(Delegate)和事件(Event)放到现在讲是有目的的:给下次写的设计模式--观察者(Obs ...
- 重温委托(delegate)和事件(event)
1.delegate是什么 某种意义上来讲,你可以把delegate理解成C语言中的函数指针,它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m,说白了就是可以把方法当作 ...
- Yii2基本概念之——事件(Event)
说起事件(event),我们可是一点都不陌生.现实生活当中的事件无处不在,比如你发了一条微博,触发了一条事件,导致关注你的人收到了一条消息,看到你发的内容:比如你通过支付宝买东西,付了款,触发一个事件 ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- 详解 Solidity 事件Event - 完全搞懂事件的使用
很多同学对Solidity 中的Event有疑问,这篇文章就来详细的看看Solidity 中Event到底有什么用? 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊. ...
- (转)C#中的委托(Delegate)和事件(Event)
转自:http://blog.chinaunix.net/uid-576762-id-2733751.html 把C#中的委托(Delegate)和事件(Event)放到现在讲是有目的的:给下次写 ...
- 事件EVENT与waitforsingleobject的使用以及Mutex与Event的区别
Mutex与Event控制互斥事件的使用详解 最近写一程序,误用了Mutex的功能,错把Mutex当Event用了. [Mutex] 使用Mutex的主要函数:CreateMutex.ReleaseM ...
- C# 事件 event 【转】
C#事件(event)解析 事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要, ...
随机推荐
- ROS节点通信(一)消息发布和订阅
目录 1.说明 2.创建工作空间 3.创建功能包 4.编写自定义传输类型文件 5.编写源代码 5.1.编写发布者代码 5.2.编写订阅者代码 6.编译 7.启动运行 8.查看ROS网络结构图 1.说明 ...
- System V|共享内存基本通信框架搭建|【超详细的代码解释和注释】
前言 那么这里博主先安利一下一些干货满满的专栏啦! 手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014. ...
- Leetcode刷题第一天-贪心
455-分饼干 链接:455. 分发饼干 - 力扣(LeetCode) 优先使用最小饼干满足最小胃口,一个娃只能分一个饼干T_T不能加 1 class Solution: 2 def findCont ...
- Oracle 数据库锁表问题及相关解决方法
Oracle 数据库锁表问题及相关解决方法 问题描述: 今天在公司运行服务的时候,需要查询300多万的数据,再进行排序之后放到kafka的消息队列中,供flink进行消费.在服务器上直接运行后,服务报 ...
- deque的rotate方法
deque对象支持旋转操作,可以将元素向左或向右循环移动. 例如: from collections import deque dq = deque([1, 2, 3, 4]) dq.rotate(1 ...
- Exadata刷机快速参考
本文以Exadata X8 HC 1/4 rack为例,介绍整个Exadata刷机的步骤. 我理解刷机最关键的就两大步骤:第一步是所有机器刷OS,第二步是使用OEDA一键刷机.至于其它所有工作都是在为 ...
- Linux-双网卡绑定bond详解
1.什么是bond 网卡bond是通过多张物理网卡绑定为一个逻辑网卡,实现本地网卡的冗余,带宽扩容和负载均衡,在生产场景中是一种常用的技术.Kernels 2.4.12及以后的版本均供bonding模 ...
- Kakfa系列丛书推荐之《深入理解Kafka:核心设计与实践原理》
pdf格式文档下载见下文 编者推荐 本书从Kafka的基本概念入手,主要从生产端.消费端.服务端等3个方面进行全面的陈述,主要内容包括Kafka的基本使用方式.生产者客户端的使用.消费者客户端的使用. ...
- 【译】我为 .NET 开发人员准备的 2023 年 Visual Studio 10 大新功能
原文 | James Montemagno 翻译 | 郑子铭 Visual Studio 2022 在 2023 年发布了许多令人难以置信的功能,为 .NET 开发人员提供了大量新工具来提高他们的工作 ...
- 源码剖析Spring依赖注入:今天你还不会,你就输了
在之前的讲解中,我乐意将源码拿出来并粘贴在文章中,让大家看一下.然而,我最近意识到这样做不仅会占用很多篇幅,而且实际作用很小,因为大部分人不会花太多时间去阅读源码. 因此,从今天开始,我将采取以下几个 ...