如何理解事件以及使用事件

2023-05-16

**疑惑点:

**对于刚接触事件来说,往往会有一种现象那就是,我为什么要用事件来调用过程,我直接调用不行吗?一样可以达到效果啊,我根本就搞不懂为啥需要事件呢?

理解直接调用和事件调用的区别

首先引用MSDN对事件的描述
执行流程是由外部发生的事情(称为“事件”)决定的
你比如说,我的按钮单击了,但是我单击后的事情由用户处理而不是我在按钮内部处理,你没理由说,我单击了按钮,我又在按钮里面自己做了一件事,那么,这是不是意味着,我的按钮单击只能做这件事了?由外部决定意味着我按钮单击了可以做不同的事情,比如你单击可以改变颜色,单击可以修改文字等等。这是由你用户写的事件处理程序决定的而不是我事先写好的
写个代码示例,给大家看看直接调用和事件触发回调的区别。
这里做了一个登陆验证,假如成功就让BC类做事。这样很容易理解是吧,按顺序来的执行。可是这样却会增加类A对类BC的依赖,假如哪天类BC的方法要修改参数,是不是又得修改类A了?而且这个仅仅只是登录成功后类BC干成功的事,那么失败的呢?也就是说这样写的类,不能适应变化,写死了,增加需求或者减少需求都得大动干戈。这是因为我们指明了要干的具体事,而事件不是这样的,事件仅仅只是通知的作用,通知外部,登录验证成功了,你该干嘛就干嘛。而不是,登录成功了,我要干你BC的事不干其他人的事了。
直接调用:

 Public Class A
        Private name As String = "admin"
        Private password As String = "1234"
        Public Sub Login(username As String, userpassword As String)
            If username = name AndAlso userpassword Then
                Dim c As New C
                Dim B As New B
                B.DoSomething()
                c.DoSomthing()

            End If

        End Sub
    End Class
    Public Class B
        Public Sub DoSomething()
            Console.WriteLine("登录成功B干活")
        End Sub
    End Class
    Public Class C
        Public Sub DoSomthing()
            Console.WriteLine("登录成功C干活")


        End Sub
    End Class
    Dim WithEvents Login As New A
    Dim testb As New B
    Dim testc As New C
    Sub Main()
        Login.Login("admin", "1234")
        Console.ReadKey()
    End Sub

事件调用:

 Public Class A
        Private name As String = "admin"
        Private password As String = "1234"
        Public Event LoginStatus(success As Boolean)
        Public Sub Login(username As String, userpassword As String)
            RaiseEvent LoginStatus(username = name AndAlso userpassword = password)
        End Sub
    End Class
    Public Class B
        Public Sub DoSomething()
            Console.WriteLine("登录成功B干活")
        End Sub
    End Class
    Public Class C
        Public Sub DoSomthing()
            Console.WriteLine("登录成功C干活")


        End Sub
    End Class
    Dim WithEvents Login As New A
    Dim testb As New B
    Dim testc As New C
    Sub Main()
        Login.Login("admin", "1234")
        Console.ReadKey()
    End Sub

    Private Sub Login_LoginStatus(success As Boolean) Handles Login.LoginStatus
        testb.DoSomething()
        testc.DoSomthing()

    End Sub
    '输出结果B做事情、C做事情
    

事件执行的过程

在事件代码里,我们用了一个登录状态的事件通知外部,登录成功与否。然后执行就看外部用户如何写,不取决于内部类对它的实现。你可以假设一个场景,你要写一个封装好的类或者程序集,给别人用,那么,你在类的内部有些操作需要别人参与,而这操作是别人写的,你没法得知,那么你怎么调用他这操作呢?这时候你直接调用是不是没法调用了?这时就用事件或委托调用,也就是回调别人的方法。
而回调别人的方法,我们获取函数地址,才能进行回调是吧,那么函数地址是肯定存在的吧(程序需要载入内存中执行),至于函数地址里的函数写了什么不需要关注,只需要得到它调用就是了,而得到它就得用到委托了,所以事件关联委托,为啥说关联呢,因为事件触发委托跟着执行,随之就调用对应的过程,而这里触发事件的称为事件的发送者,对应的过程称为事件的接收者也就是事件处理程序,这两个关联起来呢,用委托,而且是个多播委托,多播委托简单理解就是委托列表,事件触发后循环执行委托列表中的委托(广播作用),所以你可以addhandler多个委托也就是这个原因了,而且你可以测试,在任意一个事件处理程序中阻塞它会导致卡住不往下执行其他委托对应的过程,所以他不是并发执行的它是一个循环中同步执行的。
总结一下:事件触发----广播委托----执行事件处理程序。就是这么简单

关于系统事件的声明

我去反编译看了一下源码,声明Click事件的时候用的就是
Public Custom Event xx As EventHandler 而这里的EventHandler是多播委托类型的。委托知识理解请看委托那篇文章。
这它用法。

  Public Custom Event TestEvent As EventHandler
        AddHandler(value As EventHandler)
            '此处在添加委托时执行,也就是使用Addhandler TestEvent,委托  时执行
        End AddHandler

        RemoveHandler(value As EventHandler)
            '此处在移除委托时执行 , ReMovehandler TestEvent ,委托  执行
        End RemoveHandler

        RaiseEvent(sender As Object, e As System.EventArgs)
            '此处在触发事件时执行, 使用语句raiseEvent TestEvent时执行
        End RaiseEvent
    End Event

为何不用委托直接执行呢?回调当然可以用委托执行啊,主要是用起来便捷不?且看下方

多播委托模拟事件调用

 Public Class A
        Private name As String = "admin"
        Private password As String = "1234"
        Public DoWork As Action
        Public Sub Login(username As String, userpassword As String)
            If DoWork IsNot Nothing Then
                If username = name AndAlso userpassword Then
                '下面类似于触发事件后干的活
                    For Each item In DoWork.GetInvocationList
                        item.DynamicInvoke(Nothing) 
                    Next
                End If

            End If
        End Sub
    End Class
    Public Class B
        Public Sub DoSomething()
            Console.WriteLine("登录成功B干活")
        End Sub
    End Class
    Public Class C
        Public Sub DoSomthing()
            Console.WriteLine("登录成功C干活")


        End Sub
    End Class
  
    Dim WithEvents Login As New A
    Dim testb As New B
    Dim testc As New C
    Sub Main()
        Login.DoWork = [Delegate].Combine(New Action(AddressOf testb.DoSomething), New Action(AddressOf testc.DoSomthing)) '此处可以继续combine多个


        Login.Login("admin", "1234")

        Console.ReadKey()
    End Sub
  

上面就是模拟的事件,用起来是不是相当麻烦?所以事件把上面的过程都封装好了,我们只需要触发事件,增加和减少委托,还能用withevents关键字配合handle添加委托,这样就能得到多个过程的回调,管理起来很方便。

感想

不了解本质很难去真正理解这东西。再多的比喻也是别人为了让你知道这是个什么玩意,你明白了他是什么,但是你却不明白为什么要用它,所以,了解本质去了解执行过程,以及比较用它和不用它的区别,你才能真正的理解为什么要用它,再多的比喻也接近不了本质。再往深层的来说,这就是一个内存操作的东西,所有的封装只是为了让使用更便捷,相应的也懵逼很多人,不知其所以然。
再者了,上面的直接调用过程,这个那么糟糕的用法,一般都用依赖注入进行的,然后你会说,依赖注入是个什么玩意?很高端的名称,实际上很简单,就是构造函数里加个NEW(byval xx类),这就是依赖XX类注入到类。然后不还是内存吗,哈哈,Byval 获取引用类型的地址,然后再获取方法执行。

也不知道写了那么多字你们看的懂不,我反正感觉是挺乱的,哈哈,事件确实比委托难讲一点,因为事件比委托多了一层,得层层剥开。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何理解事件以及使用事件 的相关文章

  • [How TO]-如何使用Sphinx编写漂亮的文档

    快速链接 x1f449 x1f449 x1f449 个人博客笔记导读目录 全部 x1f448 x1f448 x1f448 文章目录 背景环境搭建 安装Sphinx工具创建一个项目编译项目 关键词 Sphinx readthedocs reS
  • linux 烧写树莓派sd卡,树莓派3b+从0开始:(2)SD卡的配置

    从上篇文章里已经了解到 xff0c ROM里的出厂代码决定了 xff1a GPU启动之后 xff0c 只能去SD卡上的FAT32格式的文件系统里的目录下 xff0c 寻找一个叫bootcode bin的启动文件 所以 xff0c 将SD卡里
  • android zram 命令,Android 内存管理

    概述 虚拟内存 2 1 分页 2 2 内存映射 内存不足时的处理 3 1 kswapd 3 2 LMK 虚拟机 4 1 堆空间划分 4 2 回收算法 在看这篇文章之前 xff0c 需要Linux内存管理基础 xff0c 推荐Linux 内存
  • C语言--结构体指针需要malloc

    如果定义一个结构体类型的普通变量 xff0c 可以不malloc动态申请内存 xff0c CPU会为这个结构体变量分配内存 如果定义的是一个结构体的指针 xff0c CPU会为这个指针开辟内存 xff0c 但是此时这个大小是4 xff08
  • Git分支创建命令

    Git分支创建命令 万次阅读 多人点赞 span class token number 2019 span span class token operator span span class token number 06 span spa
  • 「LSTM 之父」亲笔万字长文,只为向世人证明:深度学习不是在母语为英语的地方被发明的

    导语 xff1a 最重要的并不是谁发明了某项技术 xff0c 而是技术本身对于人类文明发展所具有的无上价值 xff01 雷锋网 AI 科技评论按 xff1a 毫无疑问 xff0c 深度学习是影响当今世界科技发展的最重要的技术之一 2018
  • 多任务学习-Multitask Learning概述

    2020 02 22 09 59 48 1 单任务学习VS多任务学习 单任务学习 xff1a 一次只学习一个任务 xff08 task xff09 xff0c 大部分的机器学习任务都属于单任务学习 多任务学习 xff1a 把多个相关 xff
  • 任奎:人工智能算法安全浅析——深度学习中的对抗攻击与防御

    2020 05 19 19 52 46 任奎 随着计算机产业发展带来的计算性能与处理能力的大幅提高 xff0c 人工智能在音视频识别 自然语言处理和博弈论等领域得到了广泛应用 在此背景下 xff0c 确保人工智能的核心 深度学习算法具有可靠
  • AI构图:AI摄影的新未来

    编辑导语 xff1a AI与摄影相结合已经不是新鲜事 xff0c 新鲜的是二者结合的方式 对于很多小伙伴来说 xff0c 拍照时最大的困扰就是不知道该如何构图 xff0c 如今AI构图已经出现了 xff0c 手机会在你拍照的时候针对情况做出
  • 浅谈民用无人机的行业化应用场景

    随着技术的发展 xff0c 人类在力学 材料学 电子技术 自动控制 计算机等方面陆续取得进步 xff0c 研制出了迷你无人机 xff0c 机型更加小巧 性能更加稳定 xff0c 同时无人机更加进步 智能化的技能 xff0c 催发了民用无人机
  • Spring Boot 整合Logback记录日志

    Spring Boot 专栏 xff1a https blog csdn net dkbnull category 9278145 html Spring Cloud 专栏 xff1a https blog csdn net dkbnull
  • 对于AI 既有期待也要思考

    近日 xff0c 在第五届世界智能大会新闻发布会上 xff0c 包括发改委 科技部 工信部等在内的多部门相关负责人表示 xff0c 将更加注重我国人工智能行业顶层设计 xff0c 全力推动人工智能产业发展 关于AI xff0c 笔者有两个问
  • 神经网络中Batch和Epoch之间的区别是什么?

    神经网络中Batch和Epoch之间的区别是什么 xff1f https mp weixin qq com s FFF6RSudAas7j2vHqP5j2Q 随机梯度下降法是一种具有大量超参数的学习算法 通常会使初学者感到困惑的两个超参数
  • 大脑升维:人工智能浪潮下的适者生存之道

    https www toutiao com a6675488003453878792 的媒介 xff0c 大家的主要精力放在思想输出的训练上 xff0c 而不是知识信息的输入上 xff0c 这样的大脑修炼速度在中维知识层面上是 慢 的 xf
  • 人工智能技术映射出来的16个行业66个应用场景!

    近期 xff0c 国际数据公司 xff08 IDC xff09 与百度AI产业研究中心 xff08 BACC xff09 联合发布了 百度大脑领导力白皮书 xff0c 白皮书中追踪了16个行业的66个应用场景 xff0c 并将人工智能在企业
  • 图像识别AI遇上对抗性图像变“瞎子”,准确率猛降90%

    https www toutiao com a6715945584722706956 在视觉方面 xff0c AI和人类的差距有多大 xff1f 来自UC Berkeley等高校的研究人员创建了一个包含7500个 自然对抗实例 的数据集 x
  • linux线程io调度策略,Linux IO调度算法

    IO调度器的总体目标是希望让磁头能够总是往一个方向移动 移动到底了再往反方向走 这恰恰就是现实生活中的电梯模型 所以IO调度器也被叫做电梯 elevator 而相应的算法也就被叫做电梯算法 而Linux中IO调度的电梯算法有好几种 一个叫做
  • 无人机入门(一)位置与电机速度控制

    无人机入门 xff08 一 xff09 作为无人机入门PX4可能过于庞大 xff0c 目前还没有支持ros noetic xff0c 而且PX4的底层框架我看也用到了ethz实验室的rotors xff0c 因此选用该模型作为入门首选 因为
  • de1 soc linux开发实例,DE1_SoC的第一次接触

    Altera 2013 教师会议上友晶科技在大陆地区正式推出了DE1 SoC xff0c 有消息称明年的亚洲创新大赛将采用SoC FPGA作为核心器件 那这也将预示着SoC FPGA正式进入了校园 作为一片性能适中的开发板 xff0c 有着
  • #include中尖括号和双引号的区别

    include lt gt 和 include 的区别 一 引用的头文件不同 include lt gt 引用的是编译器的类库路径里面的头文件 include 引用的是你程序目录的相对路径中的头文件 二 用法不同 include lt gt

随机推荐