当前位置: 首页 > news >正文

C#中委托和事件的使用总结

委托(delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。事件是一种特殊的多播委托,仅可以从声明事件的类或结构中对其进行调用。类或对象可以通过事件向其他类或对象通知发生的相关事情。本文主要介绍C#中委托和事件的使用总结。

1、委托的简单使用

一个委托类型定义了该类型的实例能调用的一类方法,这些方法含有同样的返回类型和同样参数(类型和个数相同)。委托和接口一样,可以定义在类的外部。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApplication
{delegate int Calculator(int x);class Program{static int Double(int x) { return x * 2; }static void Main(string[] args){Calculator c = Double;int result = c(2);Console.Write(result);Console.ReadKey();}}
}

2、用委托实现插件式编程

委托是一个能把方法作为参数传递的对象,通过这个可以来实现插件式编程。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApplication
{delegate int Calculator(int x);class Program{static int Double(int x) { return x * 2; }static void Main(string[] args){int[] values = { 1, 2, 3, 4 };Utility.Calculate(values, Double);//使用方法Utility.Calculate(values, x => x * 2);//使用Lambda表达式foreach (int i in values)Console.Write(i + " "); // 2 4 6 8Console.ReadKey();}}class Utility{public static void Calculate(int[] values, Calculator c){for (int i = 0; i < values.Length; i++)values[i] = c(values[i]);}}
}

3、多播委托

多播委托是指在一个委托中注册多个方法,在注册方法时可以在委托中使用加号运算符或者减号运算符来实现添加或撤销方法。创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApplication
{public delegate void ProgressReporter(int percentComplete);public class Utility{public static void Match(ProgressReporter p){if (p != null){for (int i = 0; i <= 10; i++){p(i * 10);System.Threading.Thread.Sleep(100);}}}}class Program{static void Main(string[] args){ProgressReporter p = WriteProgressToConsole;p += WriteProgressToFile;Utility.Match(p);Console.WriteLine("Done.");Console.ReadKey();}static void WriteProgressToConsole(int percentComplete){Console.WriteLine(percentComplete + "%");}static void WriteProgressToFile(int percentComplete){System.IO.File.AppendAllText("progress.txt", percentComplete + "%");}}
}

4、静态方法和实例方法对于委托的区别

一个类的实例的方法被赋给一个委托对象时,在上下文中不仅要维护这个方法,还要维护这个方法所在的实例。System.Delegate 类的Target属性指向的就是这个实例。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace BRG
{public delegate void ProgressReporter(int percentComplete);class Program{static void Main(string[] args){X x = new X();ProgressReporter p = x.InstanceProgress;p(1);Console.WriteLine(p.Target == x); // TrueConsole.WriteLine(p.Method); // Void InstanceProgress(Int32)    }static void WriteProgressToConsole(int percentComplete){Console.WriteLine(percentComplete + "%");}static void WriteProgressToFile(int percentComplete){System.IO.File.AppendAllText("progress.txt", percentComplete + "%");}}class X{public void InstanceProgress(int percentComplete){// do something    }}
}

但对于静态方法,System.Delegate 类的Target属性是Null,所以将静态方法赋值给委托时性能更好。

5、泛型委托

泛型委托和泛型的用法一样,就是含有泛型参数的委托。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApplication
{public delegate T Calculator<T>(T arg);class Program{static int Double(int x) { return x * 2; }static void Main(string[] args){int[] values = { 1, 2, 3, 4 };Utility.Calculate(values, Double);foreach (int i in values)Console.Write(i + " "); // 2 4 6 8Console.ReadKey();}}class Utility{public static void Calculate<T>(T[] values, Calculator<T> c){for (int i = 0; i < values.Length; i++)values[i] = c(values[i]);}}
}

6、事件的基本使用

声明一个事件很简单,只需在声明一个委托对象时加上event关键字就行。

例如,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example_EventTest
{class Judgment{//定义一个委托public delegate void delegateRun();//定义一个事件public event delegateRun eventRun;//引发事件的方法public void Begin(){eventRun();//被引发的事件}}class RunSports{//定义事件处理方法public void Run(){Console.WriteLine("开始运行方法");}}class Program{static void Main(string[] args){RunSports runsport = new RunSports();//实例化事件发布者Judgment judgment = new Judgment();//实例化事件订阅者//订阅事件judgment.eventRun+=new Judgment.delegateRun(runsport.Run);//引发事件judgment.Begin();Console.ReadKey();}}
}

注意:事件有一系列规则和约束用以保证程序的安全可控,事件只有 +=-= 操作,这样订阅者只能有订阅或取消订阅操作,没有权限执行其它操作。如果是委托,那么订阅者就可以使用 = 来对委托对象重新赋值(其它订阅者全部被取消订阅),甚至将其设置为null,甚至订阅者还可以直接调用委托。

事件保证了程序的安全性和健壮性。

7、事件的标准模式

.NET 框架为事件编程定义了一个标准模式。设定这个标准是为了让.NET框架和用户代码保持一致。System.EventArgs是标准模式的核心,它是一个没有任何成员,用于传递事件参数的基类。按照标准模式,事件定义委托,必须满足以下条件:

1)必须是 void 返回类型;

2)必须有两个参数,且第一个是object类型,第二个是EventArgs类型(的子类);

3)它的名称必须以EventHandler结尾。

例如,

using System;
namespace ConsoleApplication1
{class Program{static void Main(string[] args){Counter c = new Counter(new Random().Next(10));c.ThresholdReached += c_ThresholdReached;Console.WriteLine("press 'a' key to increase total");Console.WriteLine("adding one");c.Add(1);while (Console.ReadKey(true).KeyChar == 'a'){Console.WriteLine("adding one");c.Add(1);}}static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e){Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold,  e.TimeReached);Environment.Exit(0);}}class Counter{private int threshold;private int total;public Counter(int passedThreshold){threshold = passedThreshold;}public void Add(int x){total += x;if (total >= threshold){ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();args.Threshold = threshold;args.TimeReached = DateTime.Now;OnThresholdReached(args);}}protected virtual void OnThresholdReached(ThresholdReachedEventArgs e){EventHandler<ThresholdReachedEventArgs> handler = ThresholdReached;if (handler != null){handler(this, e);}}public event EventHandler<ThresholdReachedEventArgs> ThresholdReached;}public class ThresholdReachedEventArgs : EventArgs{public int Threshold { get; set; }public DateTime TimeReached { get; set; }}
}

相关文章:

C#中委托和事件的使用总结

委托&#xff08;delegate&#xff09;特别用于实现事件和回调方法。所有的委托&#xff08;Delegate&#xff09;都派生自 System.Delegate 类。事件是一种特殊的多播委托&#xff0c;仅可以从声明事件的类或结构中对其进行调用。类或对象可以通过事件向其他类或对象通知发生的…...

基于STM32的外部中断(EXTI)在嵌入式系统中的应用

外部中断&#xff08;External Interrupt&#xff0c;EXTI&#xff09;是STM32嵌入式系统中常见且重要的功能之一。它允许外部事件&#xff08;例如按键按下、传感器触发等&#xff09;通过适当的引脚触发中断&#xff0c;从而应用于各种嵌入式系统中。在STM32微控制器中&#…...

【心得】PHP的文件上传个人笔记

目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…...

深度学习之基于Pytorch和OCR的识别文本检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介深度学习与OCRPyTorch在OCR中的应用文本检测系统的关键组成部分1. 图像预处理2. 深度学习模型3. 文本检测算法4. 后处理 二、功能三、系统四. 总结 一项目简…...

三十一、W5100S/W5500+RP2040树莓派Pico<TCP_Server多路socket>

文章目录 1 前言2 简介2. 1 使用多路socket的优点2.2 多路socket数据交互原理2.3 多路socket应用场景 3 WIZnet以太网芯片4 多路socket设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 W5100S/W5500是一…...

带你精通chrony服务器

华子目录 为什么会出现Chrony&#xff1f;Linux的两个时钟NTP介绍Chrony介绍安装与配置安装Chrony配置文件分析实验1实验2chronyc命令查看时间服务器chronyc sources输出分析其他命令 常见时区 为什么会出现Chrony&#xff1f; 由于IT系统中&#xff0c;准确的计时非常重要&am…...

vs2017 编译Qt 5.11.2 源码

SDK 10.0.22000.194 有 2种编译方式 &#xff0c;第二种 看下面 方式一: 1、问题描述&#xff1a; 使用VS编译程序时&#xff0c;运行库选择多线程&#xff08;/MT&#xff09;&#xff0c;表示采用多线程静态release的方式进行编译。 但是&#xff0c;发现编译是不能通过的…...

【SpringBoot3+Vue3】四【实战篇】-前端(vue基础)

目录 一、项目前置知识 二、使用vscode创建 三、vue介绍 四、局部使用vue 1、快速入门 1.1 需求 1.2 准备工作 1.3 操作 1.3.1 创建html 1.3.2 创建初始html代码 1.3.3 参照官网import vue 1.3.4 创建vue应用实例 1.3.5 准备div 1.3.6 准备用户数据 1.3.7 通过…...

element ui修改select选择框背景色和边框色

一、修改选择框的背景色和边框色 style部分 .custom-select /deep/ .el-input__inner {color: #fff!important;border: 1px solid #326AFF;background: #04308D !important; } html部分 <el-select class"custom-select" v-model"dhvalue" placeholde…...

软件测试人员提问常用的ChatGPT通用提示词模板

如何设计有效的软件测试用例&#xff1f; 如何运用自动化测试工具进行软件测试&#xff1f; 如何进行软件的功能测试、性能测试和安全测试&#xff1f; 如何评估软件测试的质量和覆盖范围&#xff1f; 软件测试有哪些常见的缺陷和错误&#xff0c;如何识别和解决&#xff1…...

【开源】基于JAVA的服装店库存管理系统

项目编号&#xff1a; S 052 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S052&#xff0c;文末获取源码。} 项目编号&#xff1a;S052&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服…...

Jenkins代码检测和本地静态检查

1&#xff1a;Jenkins简介 Jenkins是一个用Java编写的开源的持续集成工具&#xff1b;Jenkins自动化部署可以解决集成、测试、部署等重复性的工作&#xff0c;工具集成的效率明显高于人工操作&#xff1b;并且持续集成可以更早的获取代码变更的信息&#xff0c;从而更早的进入测…...

从0开始学习JavaScript--JavaScript 字符串与文本内容使用

JavaScript中的字符串和文本内容处理是前端开发中的核心技能之一。本文将深入研究字符串的创建、操作&#xff0c;以及文本内容的获取、修改等操作&#xff0c;并通过丰富的示例代码&#xff0c;帮助读者更全面地了解和应用这些概念。 JavaScript 字符串基础 字符串是JavaScr…...

Linux--网络概念

1.什么是网络 1.1 如何看待计算机 我们知道&#xff0c;对于计算机来说&#xff0c;计算机是遵循冯诺依曼体系结构的&#xff08;即把数据从外设移动到内存&#xff0c;再从内存到CPU进行计算&#xff0c;然后返回内存&#xff0c;重新读写到外设中&#xff09;。这是一台计算机…...

C# 中的 Math 数学函数

C# 中的 Math 类提供了许多数学函数&#xff0c;用于执行各种常见的数学运算。以下是 Math 类中的一些常用方法&#xff1a; Math 数学函数 Abs: 返回指定数字的绝对值Acos: 返回指定数字的反余弦值&#xff08;弧度&#xff09;Asin: 返回指定数字的反正弦值&#xff08;弧度&…...

mybatis之主键返回

1.在mybatis的xml中加入 <insert id"insertUser" keyProperty"id" useGeneratedKeys"true" parameterType"com.UserAndOrder"> insert into Tuser(userName,passWord) values (#{userName},#{passWord} ) </insert&…...

ChatGpt3.5已经应用了一段时间,分享一些自己的使用心得.

首先ChatGpt3.5的文本生成功能十分强大&#xff0c;但是chatgpt有一些使用规范大家需要注意&#xff0c;既然chat是一种工具&#xff0c;我们就需要学会它的使用说明&#xff0c;学会chatgpt的引用语句&#xff0c;会极大的方便我们的使用。我们需要做以下的准备。 明确任务和目…...

有趣的按钮分享

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 广告打完&#xff0c;我们进入正题&#xff0c;先看效果&#xff1a; 废话不多&#xff0c;上源码&#xff1a; <button class&quo…...

论文阅读:YOLOV: Making Still Image Object Detectors Great at Video Object Detection

发表时间&#xff1a;2023年3月5日 论文地址&#xff1a;https://arxiv.org/abs/2208.09686 项目地址&#xff1a;https://github.com/YuHengsss/YOLOV 视频物体检测&#xff08;VID&#xff09;具有挑战性&#xff0c;因为物体外观的高度变化以及一些帧的不同恶化。有利的信息…...

如何将图片转为excel或word?(客户端)

演示软件&#xff1a;金鸣表格文字识别大师3.6.1&#xff08;新版本界面可能会略有不同&#xff09; 第一部分 将图片转为excel或文表混合的word 一般的软件要将图片转为可编辑的excel&#xff0c;都需要待识别的图片要有明显清晰的表格线&#xff0c;但我们程序现已克服了这…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...

用js实现常见排序算法

以下是几种常见排序算法的 JS实现&#xff0c;包括选择排序、冒泡排序、插入排序、快速排序和归并排序&#xff0c;以及每种算法的特点和复杂度分析 1. 选择排序&#xff08;Selection Sort&#xff09; 核心思想&#xff1a;每次从未排序部分选择最小元素&#xff0c;与未排…...

【题解-洛谷】P10480 可达性统计

题目&#xff1a;P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图&#xff0c;分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M&#xff0c;接下来 M M M 行每行两个整数 x , y x,y x,y&#xff0c;表示从 …...