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#中委托和事件的使用总结
委托(delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。事件是一种特殊的多播委托,仅可以从声明事件的类或结构中对其进行调用。类或对象可以通过事件向其他类或对象通知发生的…...
基于STM32的外部中断(EXTI)在嵌入式系统中的应用
外部中断(External Interrupt,EXTI)是STM32嵌入式系统中常见且重要的功能之一。它允许外部事件(例如按键按下、传感器触发等)通过适当的引脚触发中断,从而应用于各种嵌入式系统中。在STM32微控制器中&#…...
【心得】PHP的文件上传个人笔记
目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…...
深度学习之基于Pytorch和OCR的识别文本检测系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介深度学习与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?Linux的两个时钟NTP介绍Chrony介绍安装与配置安装Chrony配置文件分析实验1实验2chronyc命令查看时间服务器chronyc sources输出分析其他命令 常见时区 为什么会出现Chrony? 由于IT系统中,准确的计时非常重要&am…...
vs2017 编译Qt 5.11.2 源码
SDK 10.0.22000.194 有 2种编译方式 ,第二种 看下面 方式一: 1、问题描述: 使用VS编译程序时,运行库选择多线程(/MT),表示采用多线程静态release的方式进行编译。 但是,发现编译是不能通过的…...
【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通用提示词模板
如何设计有效的软件测试用例? 如何运用自动化测试工具进行软件测试? 如何进行软件的功能测试、性能测试和安全测试? 如何评估软件测试的质量和覆盖范围? 软件测试有哪些常见的缺陷和错误,如何识别和解决࿱…...
【开源】基于JAVA的服装店库存管理系统
项目编号: S 052 ,文末获取源码。 \color{red}{项目编号:S052,文末获取源码。} 项目编号:S052,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服…...
Jenkins代码检测和本地静态检查
1:Jenkins简介 Jenkins是一个用Java编写的开源的持续集成工具;Jenkins自动化部署可以解决集成、测试、部署等重复性的工作,工具集成的效率明显高于人工操作;并且持续集成可以更早的获取代码变更的信息,从而更早的进入测…...
从0开始学习JavaScript--JavaScript 字符串与文本内容使用
JavaScript中的字符串和文本内容处理是前端开发中的核心技能之一。本文将深入研究字符串的创建、操作,以及文本内容的获取、修改等操作,并通过丰富的示例代码,帮助读者更全面地了解和应用这些概念。 JavaScript 字符串基础 字符串是JavaScr…...
Linux--网络概念
1.什么是网络 1.1 如何看待计算机 我们知道,对于计算机来说,计算机是遵循冯诺依曼体系结构的(即把数据从外设移动到内存,再从内存到CPU进行计算,然后返回内存,重新读写到外设中)。这是一台计算机…...
C# 中的 Math 数学函数
C# 中的 Math 类提供了许多数学函数,用于执行各种常见的数学运算。以下是 Math 类中的一些常用方法: Math 数学函数 Abs: 返回指定数字的绝对值Acos: 返回指定数字的反余弦值(弧度)Asin: 返回指定数字的反正弦值(弧度&…...
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的文本生成功能十分强大,但是chatgpt有一些使用规范大家需要注意,既然chat是一种工具,我们就需要学会它的使用说明,学会chatgpt的引用语句,会极大的方便我们的使用。我们需要做以下的准备。 明确任务和目…...
有趣的按钮分享
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 广告打完,我们进入正题,先看效果: 废话不多,上源码: <button class&quo…...
论文阅读:YOLOV: Making Still Image Object Detectors Great at Video Object Detection
发表时间:2023年3月5日 论文地址:https://arxiv.org/abs/2208.09686 项目地址:https://github.com/YuHengsss/YOLOV 视频物体检测(VID)具有挑战性,因为物体外观的高度变化以及一些帧的不同恶化。有利的信息…...
如何将图片转为excel或word?(客户端)
演示软件:金鸣表格文字识别大师3.6.1(新版本界面可能会略有不同) 第一部分 将图片转为excel或文表混合的word 一般的软件要将图片转为可编辑的excel,都需要待识别的图片要有明显清晰的表格线,但我们程序现已克服了这…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
