C# 事件(Event)详解

C# 事件详解

事件(Event)是 C# 中的一种特殊类型的委托,它是基于委托的基础上构建的,用来实现事件驱动编程。在 C# 中,事件常用于处理用户输入、系统通知、数据更新等场景,允许一个对象通知其他对象某些行为已经发生。

1. 事件的基础概念

事件本质上是对委托的一种封装,提供了一种机制,使得类和对象能够通过事件通知外部发生了特定的行为。
• 委托:是对方法的引用。
• 事件:是对委托的一种封装,它提供了限制,确保只能通过特定的方式订阅和触发事件。

1.1 事件声明

事件的声明语法和委托类似,定义一个委托类型的事件。事件通常使用 event 关键字进行声明,之后可以将方法与该事件绑定。

public delegate void MyEventHandler(string message);  // 委托声明

public event MyEventHandler MyEvent;  // 事件声明

这里,MyEventHandler 是一个委托类型,MyEvent 是该类型的事件。

1.2 事件的订阅和触发

• 订阅:通过 += 运算符将方法与事件绑定。当事件触发时,所有绑定的方法会被执行。
• 触发:通过 Invoke 方法触发事件,通常由事件发布者调用。

2. 事件的基本使用

2.1 定义事件和触发事件

  1. 定义委托类型:声明事件的委托类型。
  2. 定义事件:使用 event 关键字声明事件。
  3. 触发事件:通过委托触发事件。
using System;

public delegate void MyEventHandler(string message);  // 声明委托类型

public class Publisher
{
    // 声明事件
    public event MyEventHandler MyEvent;

    // 触发事件的方法
    public void TriggerEvent()
    {
        MyEvent?.Invoke("Hello, event triggered!");  // 触发事件
    }
}

public class Subscriber
{
    // 事件处理方法
    public void OnEventTriggered(string message)
    {
        Console.WriteLine(message);
    }
}

public class Program
{
    public static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // 订阅事件
        publisher.MyEvent += subscriber.OnEventTriggered;

        // 触发事件
        publisher.TriggerEvent();
    }
}

输出:

Hello, event triggered!

2.2 事件的多播

事件支持多播,即多个方法可以订阅同一个事件。当事件触发时,所有订阅的方法都会被依次调用。

public class Subscriber
{
    public void OnEventTriggered(string message)
    {
        Console.WriteLine("First subscriber: " + message);
    }

    public void OnAnotherEventTriggered(string message)
    {
        Console.WriteLine("Second subscriber: " + message);
    }
}

public class Program
{
    public static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // 订阅多个方法
        publisher.MyEvent += subscriber.OnEventTriggered;
        publisher.MyEvent += subscriber.OnAnotherEventTriggered;

        // 触发事件
        publisher.TriggerEvent();
    }
}

输出:

First subscriber: Hello, event triggered!
Second subscriber: Hello, event triggered!

2.3 取消事件订阅

可以使用 -= 运算符取消事件的订阅。当取消订阅后,事件就不再触发已经取消的方法。

public class Program
{
    public static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // 订阅事件
        publisher.MyEvent += subscriber.OnEventTriggered;
        publisher.MyEvent += subscriber.OnAnotherEventTriggered;

        // 触发事件
        publisher.TriggerEvent();

        // 取消订阅
        publisher.MyEvent -= subscriber.OnAnotherEventTriggered;

        // 触发事件
        publisher.TriggerEvent();
    }
}

输出:

First subscriber: Hello, event triggered!
Second subscriber: Hello, event triggered!
First subscriber: Hello, event triggered!

2.4 事件的封装

C# 中的事件通过 event 关键字对委托进行了封装,限制了对事件的直接调用。事件的封装使得外部代码无法直接触发事件,只能通过 += 和 -= 来订阅和取消订阅。

public class Publisher
{
    // 声明事件
    public event MyEventHandler MyEvent;

    // 触发事件的方法,仅在发布者类内部调用
    protected virtual void OnEventTriggered(string message)
    {
        MyEvent?.Invoke(message);
    }

    // 提供公共方法触发事件
    public void TriggerEvent()
    {
        OnEventTriggered("Event triggered in Publisher");
    }
}

通过 protected virtual 方法封装事件的触发逻辑,确保只有类的内部才能触发事件。

3. 事件的常见使用场景

3.1 事件驱动编程

事件通常用于事件驱动编程模型中,特别是GUI编程和异步编程。当用户进行某些操作(如点击按钮、输入数据等)时,事件就会被触发,通知其他对象作出反应。例如:
• 用户界面(UI):用户点击按钮、输入框等控件时,触发事件(如 Button.Click)。
• 数据更新:当数据发生变化时,通过事件通知其他部分进行更新。
• 异步操作:在异步操作完成时,触发事件通知处理结果。

3.2 实现“发布-订阅”模式

事件是实现“发布-订阅”模式的典型工具。在发布-订阅模式中,发布者对象触发事件,订阅者对象响应事件。事件使得发布者和订阅者之间的耦合度降低。发布者不知道订阅者的具体实现,只是通过事件通知订阅者。

3.3 异步编程和回调

在异步编程中,事件可用于在操作完成后通知调用者或其他部分的代码。典型场景包括:
• 异步网络请求
• 文件读写操作
• 数据库查询等
例如,您可以创建一个后台任务执行完毕后触发事件通知UI线程更新界面。

3.4 定制化的事件处理

C# 事件还可以用于定制化的通知和事件处理机制。例如,在复杂的业务逻辑中,当某些条件满足时,需要触发不同的事件处理逻辑。事件可以提供灵活的事件订阅机制,使得事件响应行为能够在运行时进行动态管理。

4. 事件与委托的区别

虽然事件和委托都与方法的引用有关,但它们有一些显著的区别:
在这里插入图片描述

5. 总结

• 事件是基于委托的,提供了一个更严格的方式来管理方法的调用,尤其适用于需要通知和异步操作的场景。
• 事件允许发布-订阅模式,使得多个对象能够订阅并响应特定的事件。
• 事件通过 event 关键字封装了委托的调用,使得事件的触发只能在发布者内部进行,避免了外部代码误用。
• 事件广泛应用于UI编程、异步任务、数据更新通知等场景。
在实际开发中,事件是实现事件驱动编程、回调机制和发布-订阅模式的核心工具,它帮助减少了代码之间的耦合度,并使得代码更加灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/956951.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D

挪威文化历史博物馆在其修复工作中融入现代3D扫描技术,让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识,该博物馆被誉为挪威博物馆研究领域的领先机构。馆…

Ubuntu 24.04 LTS 系统语言英文改中文

Ubuntu 24.04 LTS 修改软件源 Ubuntu 更改软件源 修改语言 无需输入命令,为Ubuntu 24.04系统添加中文智能拼音输入法 在 setting 的 system 中按下图操作 点击“Apply Changes”。需要管理员密码,安装完成后,退出登录,重新登…

Qt按钮美化教程

前言 Qt按钮美化主要有三种方式:QSS、属性和自绘 QSS 字体大小 font-size: 18px;文字颜色 color: white;背景颜色 background-color: rgb(10,88,163); 按钮边框 border: 2px solid rgb(114,188,51);文字对齐 text-align: left;左侧内边距 padding-left: 10…

51c自动驾驶~合集48

我自己的原文哦~ https://blog.51cto.com/whaosoft/13133866 #UDMC 考虑轨迹预测的统一决策控制框架 论文:https://arxiv.org/pdf/2501.02530 代码:​​https://github.com/henryhcliu/udmc_carla.git​​ 1. 摘要 当前的自动驾驶系统常常在确…

C# 动态创建Label和ComboBox控件并修改Text

背景:在做项目的时候可能需要根据一定数量创建某些控件并修改其属性,本文以控件label、ConboBox控件进行动态创建。 程序运行前后的的Form动态图 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; …

【物联网】keil仿真环境设置 keilV5可以适用ARM7

文章目录 一、ARM指令模拟器环境搭建1. keil软件2. Legacy Support 二、Keil仿真环境设置1. 创建一个项目2. 编译器介绍(1)arm-none-eabi-gcc(2)arm-none-linux-gnueabi-gcc(3)arm-eabi-gcc(4)grmcc(5)aarch64-linux-gnu-gcc 3. 安装编译器(1)设置调试 一、ARM指令模拟器环境搭…

2024年度总结:从后端Java到全栈成长的蜕变

目录 前言1. 用数据与实践书写成长篇章2. 技术与生活的双重蜕变3. 技术的进阶与生活的绽放 前言 今年是我入行的第十年,也是记录在CSDN平台上的第五年。这五年来,我始终坚持记录成长的点滴,将个人事业与博客创作紧密相连。一路走来&#xff0…

U-Net - U型网络:用于图像分割的卷积神经网络

U-Net是一种专为图像分割任务设计的卷积神经网络(CNN),最初由Olaf Ronneberger等人于2015年提出。它被广泛应用于医学影像分析、遥感图像分割、自动驾驶和其他许多需要对图像进行像素级分类的任务中。U-Net具有强大的特征提取和恢复能力&…

SpringCloud基础一

前后端分离开发 前后端分离开发后,前后端代码不在混合在同一个maven工程中,而是分为前端工程和后端工程。此时前后端代码并行开发,可以加快项目的开发进度在前后端代码分离后,此时后端工程会打包部署到Tomcat上,前端工…

MFC中添加Richedit2.0控件导致程序无法运行的解决方法mfc richedit2 Detected memory leaks! 及控件使用

错误:拖Richedit2.0控件到界面,编译提示mfc richedit2 Detected memory leaks! 原因:在MFC中添加Richedit2.0控件,可能会导致程序出错或无法运行。这是由于RichEdit没有初始化导致的。 解决:在 继承自CWinApp的类中的…

每打开一个chrome页面都会【自动打开F12开发者模式】,原因是 使用HBuilderX会影响谷歌浏览器的浏览模式

打开 HBuilderX,点击 运行 -> 运行到浏览器 -> 设置web服务器 -> 添加chrome浏览器安装路径 chrome谷歌浏览器插件 B站视频下载助手插件: 参考地址:Chrome插件 - B站下载助手(轻松下载bilibili哔哩哔哩视频&#xff09…

【电视盒子】HI3798MV300刷机教程笔记/备份遥控码修复遥控器/ADB/线刷卡刷/电视盒子安装第三方应用软件

心血来潮,看到电视机顶盒满天飞的广告,想改造一下家里的电视盒子,学一下网上的人刷机,但是一切都不知道怎么开始,虽然折腾了一天,以失败告终,还是做点刷机笔记。 0.我的机器 年少不会甄别&…

USART_串口通讯轮询案例(HAL库实现)

引言 前面讲述的串口通讯案例是使用寄存器方式实现的,有利于深入理解串口通讯底层原理,但其开发效率较低;对此,我们这里再讲基于HAL库实现的串口通讯轮询案例,实现高效开发。当然,本次案例需求仍然和前面寄…

AI绘画入门:探索数字艺术新世界(1/10)

引言:AI 绘画的兴起与现状 在科技飞速发展的当下,AI 绘画如同一场艺术领域的风暴,正以惊人的速度席卷而来,彻底改变着我们对艺术创作的认知。近年来,AI 绘画相关的话题屡屡登上热搜,从社交媒体上各种 AI 生…

多线程杂谈:惊群现象、CAS、安全的单例

引言 本文是一篇杂谈,帮助大家了解多线程可能会出现的面试题。 目录 引言 惊群现象 结合条件变量 CAS原子操作(cmp & swap) 线程控制:两个线程交替打印奇偶数 智能指针线程安全 单例模式线程安全 最简单的单例&…

Ubuntu -- 几行命令使用Ollama部署本地AI大模型, 仅调用api, 快速测试api效果

需求 需要在本地快速部署一个大模型, 然后使用 局域网 的其他电脑进行 api调用为了快速测试, 大模型选择了 qwen2:0.5B 进行快速测试 开始 下载安装 ollama curl -fsSL https://ollama.com/install.sh | sh验证安装 ollama --version下载安装模型并运行 ollama run qwen2:…

无降智o1 pro——一次特别的ChatGPT专业模式探索

这段时间和朋友们交流 ChatGPT 的使用心得,大家都提到一个很“神秘”的服务:它基于 O1 Pro 模型,能够在对话里一直保持相对高水平的理解和回复,不会突然变得“降智”。同时,整体使用还做了免折腾的网络设置——简单一点…

1. 基于图像的三维重建

1. 基于图像的三维重建 核心概念三维重建中深度图、点云的区别?深度图点云总结 深度图到点云还需要什么步骤?1. **获取相机内参**2. **生成相应的像素坐标**3. **计算三维坐标**4. **构建点云**5. **处理颜色信息(可选)**6. **去除…

国内有哪些著名的CRM系统提供商?

嘿,你有没有想过,在这个信息爆炸的时代里,企业怎么才能更好地管理客户关系呢?答案就是使用高效的CRM系统。今天我就来给大家聊聊那些在国际上非常有名的CRM系统提供商吧。 悟空CRM 首先不得不提的就是悟空CRM了!这可…

QTableWidget的简单使用

1.最简单的表格示例&#xff1a; ui->tableWidget->setRowCount(2);// 设置行数ui->tableWidget->setColumnCount(3);// 设置列数&#xff0c;一定要放在设置行表头之前QStringList rowHeaderList;// 行表头rowHeaderList << QStringLiteral("姓名"…