C# 事件(event)

news2024/11/24 5:45:18

目录

一、概述

二、事件和委托的区别

委托和事件的概念

委托和事件的作用

委托和事件的区别

三、事件的基本用法

结束


一、概述

事件是一种特殊的多播委托,仅可以从声明事件的类(或派生类)或结构(发布服务器类)中对其进行调用。 如果其他类或结构订阅该事件,则在发布服务器类引发该事件时,将调用其事件处理程序方法

可以将事件标记为public、private、protected、internal、protected internal 或 private protected。 这些访问修饰符定义该类的用户访问该事件的方式。 

事件在我们平时开发中用的还是比较多的,大部分时候用在框架中,比如 Winform 中的 Timer 组件,如下面代码,Timer.Elapsed 就是一个事件

//实例化Timer类,
var Timer = new System.Timers.Timer();
//设置间隔时间(毫秒);
Timer.Interval = IntervalTime;
//到达时间的时候执行事件;
Timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
//设置是执行一次(false)还是一直执行(true);
Timer.AutoReset = true;

在Visual Studio 2022 中的反编译,我们可以看到这个事件的具体写法

在我们平时所用的框架中,只要用 += 去添加方法,那基本都是事件写的。 

二、事件和委托的区别

参考一些网上的资料:

委托和事件的概念

委托

C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。它本质上也是一个类。

它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法。

事件

事件由对象引发,通过我们提供的代码来处理。一个事件我们必须订阅(Subscribe)他们,订阅一个事件的含义就是提供代码,在这个事件发生时执行这些代码,这些代码称为事件处理程序。

事件是在委托类型变量前加上 event 关键字,其本质是用来对委托类型的变量进行封装,类似于类的属性对字段的封装。

委托和事件的作用

委托

可以把方法当参数传递,可以避免在程序中大量使用 if-else(switch) 语句,同时使得程序具有更好的可扩展性。C#2.0 之后出现了 匿名函数 和 lambda表达式 也是 Delegate 演化而来。

事件

事件的使用一般通过发布者和订阅者来进行。发布者会在某一条件下触发某事件,订阅者可以通过订阅该事件,来对该事件的触发做出反应。

比如,设计模式中的观察者模式.

委托和事件的区别

1、事件是委托的封装 —— 是一种特殊的委托。

2、事件里面其实就是两个方法(即 add_event() 和 remove_event())和一个私有的委托变量,这两个方法里面分别是对这个私有的委托变量进行的合并和移除,当调用事件的 += 时其实是调用的事件里面的 add_event() 方法,同样 -= 调用的是 remove_event() 方法。

3、在注册和注销事件上:

委托可以使用 = 和 += 来将函数注册到委托的变量上,使用 -= 来将函数注销。

事件则有着更严格的限制,事件只能使用 += 来将函数注册到其上,使用 -= 来将函数注销。

三、事件的基本用法

在一些比较老的项目源码中还是能看到 delegate 配合 event 这种写法的, delegate 在平时工作中使用还是比较少的,个人一般使用 Action 和 Func 委托,主要是 delegate 使用起来不是特别方便,在下面的案例中,我也会以 Action 和 Func 为主。

案例1

下面使用 delegate 配合 event 的写法

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

namespace 事件demo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            User1 user1 = new User1();
            User2 user2 = new User2();

            MessageHandle.Receive("回家吃饭了");

            Console.ReadKey();
        }
    }


    public class MessageHandle
    {
        public delegate void OnMessage(string message);

        public static OnMessage OnMessageEvent = null;

        public static void Receive(string message)
        {
            if (OnMessageEvent != null)
                OnMessageEvent(message);
        }

        private MessageHandle() { }
    }


    public class User1
    {
        public void Receive(string msg)
        {
            Console.WriteLine("User1 收到消息:" + msg);
        }

        public User1()
        {
            MessageHandle.OnMessageEvent += Receive;
        }
    }

    public class User2
    {
        public void Receive(string msg)
        {
            Console.WriteLine("User2 收到消息:" + msg);
        }

        public User2()
        {
            MessageHandle.OnMessageEvent += Receive;
        }
    }

}

运行

在上面的代码中,可以直接这么写,效果一样的,我更推荐多使用 Action ,Func 的写法

    public class MessageHandle
    {
        public static Action<string> OnMessageEvent = null;

        public static void Receive(string message)
        {
            if (OnMessageEvent != null)
                OnMessageEvent(message);
        }

        private MessageHandle() { }
    }

案例2

在 winform 开发中,我们经常用到定时器,有时候,定时器需要一直使用,并且在很多类中使用,那么我们可以使用一个定时器,做成一个订阅机制就行了,这样可以更加方便的管理。

using System;
using System.Threading;
using System.Windows.Forms;

internal class ScanTimer
{
    /// <summary>
    /// 定时器回调事件
    /// </summary>
    public static event Action ScanEvent;

    //定时器
    private static System.Timers.Timer Timer = null;
    //间隔时间
    private static int IntervalTime = 1000;

    private static void Elapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        if (ScanEvent != null)
            ScanEvent();
    }

    /// <summary>
    /// 打开定时器
    /// </summary>
    public static void Start()
    {
        Timer.Enabled = true;
    }
    
    /// <summary>
    /// 关闭定时器
    /// </summary>
    public static void Stop()
    {
        Timer.Enabled = false;
    }


    static ScanTimer()
    {
        //实例化Timer类,
        Timer = new System.Timers.Timer();
        //设置间隔时间(毫秒);
        Timer.Interval = IntervalTime;
        //到达时间的时候执行事件;
        Timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
        //设置是执行一次(false)还是一直执行(true);
        Timer.AutoReset = true;
    }

    private ScanTimer() { }
}

比如,上位机有些项目,需要每天固定的时间做某些事情,比如保存昨天的生产报表,我们就要写一个定时器,反复的进行判断

调用方法:

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

namespace 事件demo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            CheckTimer checkTimer = new CheckTimer();
            checkTimer.Init();

            ScanTimer.Start();

            Console.ReadKey();
        }
    }

    public class CheckTimer
    {
        public void Init()
        {
            ScanTimer.ScanEvent += Check;
        }

        public void Check()
        {
            if (DateTime.Now > DateTime.Parse(DateTime.Now.ToShortDateString() + " 12:00:00"))
                Console.WriteLine("当前时间:" + DateTime.Now.ToString() + " 大于时间:" + DateTime.Now.ToShortDateString() + " 12:00:00");
            else
                Console.WriteLine("当前时间:" + DateTime.Now.ToString() + " 小于时间:" + DateTime.Now.ToShortDateString() + " 12:00:00");
        }
    }
}

运行:

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Revit中门窗的翻转控件该如何添加?

一、门窗的翻转控件该如何添加? 放置过门窗的小伙伴会发现&#xff0c;门窗是可以进行左右前后进行翻转的&#xff0c;可以通过这些小按钮或是空格键进行门窗的朝向&#xff0c;十分的人性化&#xff0c;可以帮我们更好的放置门窗。一般上我们创建门窗族时系统会自动为我们添加…

我们和ChatGPT聊了聊BI的未来

ChatGPT是什么? ChatGPT是OpenAI开发的聊天机器人&#xff0c;2022年11月上线&#xff0c;迅速火爆全球&#xff0c;1周突破100万用户&#xff0c;仅用2个月全球突破1亿用户&#xff0c;碾压史上所有应用程序。美国有学生用ChatGPT写论文拿下全班最高分&#xff0c;ChatGPT可以…

微信支付链接二维码生成

1、进入composer官方网站&#xff0c;搜索phpqrcode安装包 composer命令安装 composer require aferrandini/phpqrcode 生成二维码图片的公共方法&#xff1a; // 公用二维码生成 static function setQrcode($url){//二维码图片保存路径$path advert/qrcode/.date("Ymd&q…

JavaScript高级二、构造函数常用函数

零、文章目录 JavaScript高级二、构造函数&常用函数 1、深入对象 &#xff08;1&#xff09;创建对象三种方式 利用对象字面量创建对象 利用 new Object 创建对象 利用构造函数创建对象 案例如下&#xff1a; <!DOCTYPE html> <html lang"en"&g…

干货分享:小红书商业化+微信社区运营,引流自动裂变拓客方案

干货分享&#xff1a;小红书商业化微信社区运营&#xff0c;引流自动裂变拓客方案 背景&#xff1a;2023为止小红书基本已是当代年轻人都会下载和使用的软件了&#xff0c;小红书是生活方式平台和消费决策入口&#xff0c;通过智能机器人学习和对用户的精准智能匹配走红&#x…

chatgpt赋能python:Python中datetime的用法

Python 中datetime的用法 介绍 在 Python 中&#xff0c;datetime 是一个非常重要和常用的模块&#xff0c;它提供了很多操作日期和时间的函数。datetime 模块中最主要的三个类是 datetime、date 和 time。其中 datetime 类是 date 和 time 的组合&#xff0c;所以这里只介绍…

C++读写文本文件

2023年5月30日&#xff0c;周二下午&#xff1a; 这几天学习了C对文本文件的读写&#xff0c;写篇博客来总结一下 由于内容太多&#xff0c;我没法一次性写完&#xff0c;之后会不定期更新的 我使用C标准库中的fstream库来读写文本文件 用fstream来读写文本文件有两种方式&a…

element dialog对话框中select/cascader 弹窗不跟随问题

Element 在使用对话框中出现的情况 Select 选择器 Cascader 级联选择器 在这两种组件组合使用是出现了滑动 弹出框不跟随情况&#xff0c;如下 出现这种情况原因是因为弹出框相对的位置是body&#xff0c;展示后&#xff0c;如果body不动&#xff0c;所以弹窗位置不会发生改变…

研发工程师玩转Kubernetes——创建一个测试容器

测试容器并不是什么都没有的容器&#xff0c;只是它没有我们期望的常驻进程。我们常用它来做一些测试。 举个例子&#xff0c;在《研发工程师玩转Kubernetes——自动扩缩容》中我们使用本地wrk进行了压力测试。如果我们希望进入容器手工调用wrk&#xff0c;该怎么做呢&#xff…

后摩尔时代,洞见第三代功率半导体器件参数测试的趋势和未来!

前言 2022年&#xff0c;全球半导体产业连续高增长&#xff0c;进入调整周期。与此形成对比&#xff0c;在新能源汽车、光伏、储能等需求带动下&#xff0c;第三代半导体产业保持高速发展&#xff0c;全球化供应链体系正在形成&#xff0c;竞争格局逐步确立&#xff0c;产业步…

网络协议格式 | 以太网帧、ARP数据报、IP数据报、UDP数据报、TCP数据报

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

计算机视觉实战--OpenCV进行红绿灯识别

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 OpenCV是一个开源的计算机视觉库&#xff0c;可以用于实现各种图像和视频处理任务&#xff0c;包括红绿灯识别。可以帮助自动驾驶汽车、智能交通系统等设备准确地识别红绿灯的状态&#xff0c;以便做出正确的决策。今天&a…

2022-Deep generative molecular design reshapes drug discovery-分子生成设计重塑药物发现

文章目录 药物发现中的深度生成模型化合物/分子的表示 Deep Generative Models递归神经网 RNN变分自动编码器 VAE生成性对抗网络 (Generative Adversarial Networks, GANs)Flow-based models强化学习(Reinforcement Learning, RL) 在小分子药物设计中的应用生成有效的小分子生成…

X2000 freeRTOS usb_bulk通信

例程 官方例程..\freertos\example\usb\device\gadget_generic_bulk.c&#xff0c;代码如下&#xff1a; #include <common.h> #include <usb/gadget_bulk.h> #include <os.h>static const struct gadget_id bulk_id {.vendor_id 0x1CBE,.product_id 0x…

3.1. 字符串与StringBuilder

1. 字符串&#xff08;String&#xff09; 在Java中&#xff0c;字符串由String类表示。字符串是一系列字符的组合&#xff0c;用于表示文本数据。字符串是不可变的&#xff0c;这意味着一旦创建了一个字符串对象&#xff0c;就不能修改它的内容。 创建字符串 创建字符串的方…

真的裂开了呀,现在的00后,真是卷死了,辞职信已经写好了

谁说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;上个月我们公司来了个00后&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪22K&#xff0c;都快接近我了。 后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 …

Android 应用打包和编译技术

Android 应用打包和编译技术非常重要&#xff0c;因为它们可以帮助开发者将代码转换成可执行的应用程序&#xff0c;并优化应用程序的性能和稳定性。 1. Gradle Gradle 是基于 Groovy 语言和 Java 虚拟机&#xff08;JVM&#xff09;运行的构建工具&#xff0c;通过它来配置应…

【目标检测】yolov5代码实战

文章目录 一、yolov5介绍二、yolov5安装2.1 yolov5的源码下载2.2 预训练模型下载2.3 安装yolov5的依赖项2.4 检测是否安装成功 三、yolov5训练自己的数据集参考资料 一、yolov5介绍 YOLO 是 “You only look once” 缩写 , 是将图像划分为网格系统的对象检测算法&#xff0c;网…

110.(cesium篇)cesium动态河流流水

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: cesium动态河流流水 下面献上完整代码,代码重要位置会做相应解释 <html lang="en

HHDESK及HHDBCS快捷升级功能

为提升用户体验&#xff0c;HHDESK及HHDBCS新增了一项功能&#xff0c;一键升级。 1 使用软件时快捷升级 在产品首页点击帮助&#xff0c;选择软件升级 弹出如下对话框&#xff1b;点击确定 随即弹出对话框&#xff1b;点击浏览&#xff0c;选择下载到本机上的新版本产品…