C#中的委托与事件笔记——进阶

C#中的委托与事件详解 委托(Delegate)是C#中的一种类型,用于引用具有特定参数列表和返回类型的方法,本质上是一种类型安全的函数指针。它允许将方法作为参数传递、存储在变量中或从方法返回。委托支持多播,可以组合多个方法,并且是.NET事件模型的基础。C#中常用的内置委托类型包括Action、Func和Predicate,分别用于无返回值、有返回值和返回布尔值的方法。 事件(Event)是建立在委托基础上的高级特性,用于实现观察者模式(发布-订阅模型)。事件封装了委托,限制外部只能通过+=和-=操作订阅或取消订阅,提供了更安全 阅读详情
一、委托基础
  1. 委托类型
    • 在 C# 里能写出的所有委托基本上都是多播委托(MulticastDelegate),常规方式无法写出普通的委托(Delegate),底层实现中才可能出现 Delegate 类型。
    • 多播委托可以添加多个方法,使用 += 运算符添加方法,其内部的 invocationList 用于存储方法。

      当委托为普通委托时,invocationList 指向一个方法;为多播委托时,它是一个数组,可存储多个方法。

    • 可通过 GetInvocationList 方法获取 invocationList 中的所有委托,该方法返回一个 Delegate 数组。
  2. 委托特性及问题
    委托内部存储了一个方法列表(数组),因此委托存在一些问题:
    • 调用报错中断:调用委托时,如果其中一个委托报错,后面的委托不会被调用。

    • 返回值问题:如果委托有返回值,注册多个方法时,调用委托(Invoke)的返回值会是最后一个方法的返回值。

    • 移除方法时间复杂度:使用 -= 运算符移除方法时,时间复杂度是 O(n)。

      从委托方法列表中Remove一个方法时,对该方法的查找是从后往前进行的

      若移除最早添加的方法,查找时间会显著增加。

    • 线程不安全:对委托数组的添加或删除操作没有提供线程锁,线程不安全。

      事件(对委托的一种封装)是线程安全的

  3. 委托与函数指针的区别
    • 委托可以指向多个函数:委托可以指向多个函数,而函数指针做不到。
    • 委托可以指向同一函数多次:委托可以指向同一个函数多次,在调用时会按顺序多次调用该函数,函数指针无法实现。
    • 包含对象信息:在 C# 中,将方法添加到委托时,方法所在类的实例信息也会作为信息传递过去,委托的函数引用包含了方法所在对象的信息;而 C++ 中的函数指针只是函数的入口地址,不具备这些信息。
  4. 委托的异步调用(几乎已弃用)
    • 委托提供了 BeginInvoke 和 EndInvoke 方法用于异步调用,但在 .NET Core 及后续版本中不再使用。
    • 在旧版本中,BeginInvoke 会在另一个线程上运行任务,返回一个 IAsyncResult 类型,可通过其 IsCompleted 属性判断任务是否完成,使用 EndInvoke 结束调用并获取结果。现在通常使用 async/await 和 Task 进行异步编程。

    在 UI 开发(如 WinForm、WPF)中,控件的 Dispatcher 有 BeginInvoke 方法,但一般采用开多线程或异步任务,完成任务后回到 UI 线程操作控件或调用 Dispatcher.Invoke。

二、逆变与协变
  1. 概念
    • 协变(Covariance):把一个派生类转换为它的父类,通常可使用隐式转换。在委托中,若委托返回值类型为父类(如 object),可以添加返回值为派生类(如 string)的方法,这是允许的,即从派生类转为父类。
    • 逆变(Contravariance):把一个父类对象转换为它的派生类,通常使用显式转换。在委托中,若委托参数类型为派生类(如 string),可以添加参数类型为父类(如 object)的方法,相当于把父类逆变成派生类。

    .NET 中原生的强类型委托除了Action和Func外,还包含一个Predicate(该委托并不常用),其返回值一定是布尔值,参数只能有一个int,常用于筛选,但在实际中,返回值为布尔值且参数为一个的lambda表达式通常会被转换为 Func 而非 Predicate。

  2. 委托的逆变与协变:委托的逆变与协变指的是其传参以及返回值,泛型委托还提供了泛型逆变与协变,如 Action 中的 in 表示参数协变,IEnumerable 中的 out 表示参数逆变。
    在这里插入图片描述
三、委托与接口的比较

如果委托是为了实现将函数作为参数进行传参的话,为什么不使用接口呢?

使用接口的缺点:

  • 不灵活:使用接口传递不同形式参数时,需要定义多种接口,且必须有类去实现接口,繁琐且不实用。

    比如使用LINQ时,要频繁传入各种形式的函数

  • 暴露公共成员:传递接口对象实际上是传递类的实例引用,可能会暴露类中的其他公共成员,引发不必要麻烦。
  • 无法使用多播功能:接口无法像委托那样提供添加和删除等多播功能。
  • 方法封装固定:类的方法封装好后难以定制更改,而匿名委托(如lambda表达式)可随时声明,能使用当前作用域下的变量,提供高度灵活性。
  • 内置强类型委托丰富:C# 内置了很多强类型委托,如 Action、Func、Predicate 等,以及处理标准事件的 EventHandler,无需编写大量接口来满足不同参数和返回值需求。
四、事件
  1. 事件的本质
    • 事件使用 event 加上委托类型和事件实例名称声明,实际上是一个语法糖:
      1. 事件将委托以私有变量的形式封装在类内,外部无法直接访问和调用 Invoke 方法。
      2. 事件对委托进行了封装,定义了 add 和 remove 两个方法,类似于属性的 get 和 set,用于合并和移除委托。
      3. 事件提供了线程安全性,在add与remove中使用 Interlocked.CompareExchange 进行线程锁操作。
  2. 自定义事件
    • 可以像自定义属性一样自定义事件的 add 和 remove 方法。例如使用 List<Action> 存储委托,add 方法调用 List 的 Add 方法添加委托,remove 方法调用 List 的 Remove 方法移除委托,还可提供公共方法调用委托列表中的每个委托。但自定义时要注意多线程安全性问题,若不提供线程安全措施,在多线程环境下频繁进行 add 或 remove 操作可能会出现问题。

    • 在某些情况下,如 WPF 中使用 MVVM 模式实现 RelayCommand 类时,需要对事件的 add 和 remove 方法进行定制化,可使用 CommandManager 的静态事件 RequerySuggested 对传入的函数进行注册或删除。也可以进行一些特殊定制,但不具有实际意义,只是为了展示其可行性。
      不使用自动属性

      运行结果为 3 method registered

C#委托和事件 C#委托和事件 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 开发工具与关键技术:C# 作者:吴锦华 撰写时间:2021/10/28 一、委托的概念 委托从字面上理解就是一种代理,类似于房屋中介,由租房人委托中介为其租赁房屋。 在 C# 语言中,委托则委托某个方法来实现具体的功能。 委托的特点: 1、委托是一种引用类型,虽然在定义委托时与方法有些相似,但不能将其称为.. 阅读详情

相关推荐

c#中的委托与事件

“在C#中,委托与事件是不容易弄清楚的两个概念。本文主要介绍这两个概念以及它们的用法。” 一、委托 首先,我们来看委托。委托本质上是函数或方法的指针,也就是说,委托对象的值就是指向一个方法的指针。因此,对于一个委托类型,可以创建它的实例,并使这个实例指向一个具体的方法。而这个方法的签名(即方法的参数个数、每个参数的类型以及方法的返回值)必须要与委托类型的定义一致。无论方法具体完成什么功能,只要其签名与委托定义一致即可。在C#中,定义委托使用delegate关键字。来看一个例子,以下...

qq_20350847的博客 644

Unity基础之C#进阶篇笔记4:委托和事件

Unity基础之C#进阶篇笔记4:委托和事件委托1.委托是什么2.基本语法3.定义自定义委托4.使用定义好的委托5.委托变量可以存储多个函数(多播委托)6.系统定义好的委托7.总结8.练习题事件1.事件是什么2.事件的使用3.为什么有事件4.总结5.练习题匿名函数1.什么是匿名函数2.基本语法3.使用4.匿名函数的缺点5.总结6.练习题Lambad表达式1.什么是lambad表达式2.lambad表达式语法3.使用4.闭包5.总结6.练习题 委托 1.委托是什么 //委托是 函数(方法)的容器

qq_42481369的博客 1661

【C#进阶3-2】C#委托、事件

一、目录 【Unity3D从入门到进阶】文章目录及设置这个专栏的初衷 二、C#委托 2-1、描述 C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。 委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。 2-2、声明委托 委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。 例如,假设有一个委托: p

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 1881

C#笔记进阶篇07 事件

C#笔记进阶篇07 事件 ——本系列是基于人民邮电出版社《C#2008 C#图解教程》、清华大学出版社《C#入门经典(第五版)》两本书的自学C#笔记,如果您发现了本文的纰漏,还望不吝指正。 写在前边 ...

Tervor_HAN的博客 362

手把手教你用Qt和QScada框架,从零搭建一个简易的工业组态监控界面

本文详细介绍了如何使用Qt和QScada框架从零搭建工业组态监控界面,涵盖环境配置、界面设计、动态数据绑定及高级功能实现。通过实战案例演示,帮助开发者快速掌握SCADA系统开发技巧,提升工业自动化项目的开发效率。

weixin_32932149的博客 340

CST高阶技巧:用周期性边界快速仿真共面波导色散特性(含JDM求解器优化)

本文详细介绍了在CST仿真软件中,利用周期性边界条件结合JDM本征模求解器,高效分析共面波导色散特性的高阶技巧。该方法通过仿真一个单元胞而非整条传输线,大幅提升计算效率,并提供了从建模、边界设置、求解器优化到后处理的完整工作流程,是高频电路设计的实用指南。

weixin_29280219的博客 403

C#中委托和事件

关于委托和事件分享三个博客内容: 首先说明下: (1)C#中事件:事件时属于类的成员,所以要放在类的内部。 (2)委托属于一个定义,是和类、接口类似的,通常放在外部。 (因为大多数委托都要被重用) 委托定义在类里面还是类外面视情况而定,一般定义在与类定义平级部分, 且用public修饰,便于外部调用。 若定义在类的内部,则必须通过调用该类的成员才能取得其委托的引用, 频繁...

andu1644的博客 1万+

Python实战:3种高效方法将txt转csv(附pandas对比测试)

本文针对Python中将txt文件转换为csv格式的需求,深度评测了open()、csv模块和pandas三种主流方法。通过详尽的性能对比测试,从执行效率、内存占用和适用场景等维度提供选型指南,帮助开发者根据数据规模与复杂度选择最高效的转换方案。

weixin_29073241的博客 263

c# 中的事件与委托详解

在浏览之余发现了这篇好文章,转载于此,原文链接: https://www.cnblogs.com/newcapecjmc/p/7084026.html C#中委托和事件 关于委托和事件分享三个博客内容: 首先说明下: (1)C#中事件:事件时属于类的成员,所以要放在类的内部。 (2)委托属于一个定义,是和类、接口类似的,通常放在外部。 (因为大多数委托都要被重用) 委托定义在类里面还是类外面视情况而定,一般定义在与类定义平级部分, 且用public修饰,便于外部调用。 若定义在类的内部

qq_39024280的博客 6244

(目录)微气候模型ENVI-met模拟的基本使用教程

ENVI-met模拟操作系列(一) 介绍:

ysqzhatian的博客 2万+

Matlab/simulink频率响应分析方法

Matlab/Simulink仿真系列问题一.电气模块与信号模块 一.电气模块与信号模块

virtuoso~晓晓 3万+

C# 委托与事件总结

C# 中的委托和事件可以说是超级拦路虎了,一个不小心就容易让人直接放弃学习。最近几天花了点时间钻研了一下,查看了一些资料,希望做个总结。 我还达不到技术大佬的级别,主要就是做个**自我总结**,很推荐大家看一下我下面发的参考资料里的文章和视频,那些是真正的大佬产出的内容。

萌宅鹿的技术小屋 2617

软硬件融合加速技术系列文章

目录 文章目录目录计算机组成原理Linux 操作系统原理处理器进程管理内存管理I/O 系统文件系统网络协议栈资源管理设备管理GPUFPGASmartNIC/DPU 计算机组成原理 《计算机组成原理 — 冯诺依曼体系结构》 《计算机组成原理 — 基本硬件设备》 《计算机组成原理 — CPU 中央处理器》 《计算机组成原理 — 指令系统》 《计算机组成原理 — 总线系统》 《计算机组成原理 — 存储系统》 《计算机组成原理 — 输入输出系统 — 存储控制器接口类型》 《计算机组成原理 — 服务器》 《计算机组成

烟云的计算 6806

C#中的委托和事件

这行代码定义了一个名为MyDelegate的委托类型,它可以引用任何具有void返回类型并接受一个string参数的方法。

weixin_73376914的博客 2349

YOLOv8改进 | Conv篇 | 轻量级下采样方法ContextGuided(大幅度涨点)

ContextGuided通过创新的局部-全局协同机制,解决了传统下采样方法中细节丢失与上下文缺失的核心痛点。实验证明其在YOLOv8上可实现最高2.6%的mAP提升,且计算开销增加不足5%。这种即插即用的设计为实时目标检测系统提供了新的优化方向。创新启示:轻量化不代表简单裁剪,智能信息融合才是未来方向!下一步探索与Transformer结合构建混合架构多尺度上下文融合机制3D点云中的扩展应用资源获取完整训练代码:[GitHub链接]预训练模型:[Google Drive链接]讨论话题。

QQ_778132974的博客 290

6、核函数与再生核希尔伯特空间:原理、应用与实践

本文系统介绍了核函数与再生核希尔伯特空间(RKHS)的理论基础、核心性质及其在机器学习和信号处理中的广泛应用。文章从核方法的优势出发,阐述了其在非线性建模、正则化和算法核化方面的独特价值,并深入探讨了正定核、Mercer定理、表示定理等关键理论。通过构建多种标准核与工程专用核,展示了核函数的设计灵活性。结合支持向量回归(SVR)模型与多个MATLAB示例,详细说明了核方法的实际应用流程与操作技巧。最后,总结了核方法的应用领域、未来发展方向及学习实践建议,为读者提供了一套完整的理论与实践指南。

z2a3b4c5d的博客 145

C# 之委托与事件详解

C#委托与事件核心机制解析 摘要:本文深入探讨C#中委托与事件的核心机制。委托作为类型安全的函数指针,支持多播和泛型应用(如Func/Action)。事件基于委托实现发布-订阅模型,采用标准模式定义和触发。文章详解了协变/逆变、异步调用、弱事件等高级特性,并展示了在LINQ和设计模式(如观察者模式)中的实际应用。通过自定义事件访问器和WeakEventManager等技术,开发者可以构建松耦合、高效且内存安全的响应式系统。这些机制共同构成了C#事件驱动编程的基础,为复杂应用程序提供了灵活的架构方案。

weixin_45590420的博客 1920

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

理解 C# 中的委托与事件

委托在 C# 中可以被看作是一种类型安全的函数指针。它允许我们将方法作为参数进行传递,就如同传递其他数据类型一样。简单来说,委托定义了一个方法签名,任何与该签名匹配的方法都可以赋值给这个委托变量。这样,我们就可以在运行时动态地决定调用哪个方法。// 调用委托,等同于调用CalculateSum(3, 5)// 输出8事件本质上是一种特殊的委托实例,它为对象间的交互提供了一种发布 - 订阅机制。一个对象(发布者)可以定义一个或多个事件,其他对象(订阅者)可以注册这些事件,并在事件触发时执行相应的操作。

2401_85253577的博客 906

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

C#委托与事件

C#委托与事件,包含Action,Func

布小禅的博客 2378

掌握 C# 中的委托与事件机制

委托是一种类型安全的函数指针,可以用于引用一个或多个方法。通过委托,可以将方法作为参数传递给其他方法,从而实现回调和灵活的行为封装。委托的定义类似于定义方法签名,它指定了可以被引用的方法的返回类型和参数列表。// 定义一个委托// 使用委托// 调用委托// 将方法赋值给委托");// 输出:Hello, Delegates!在上面的示例中,是一个委托类型,它可以引用任何具有void返回类型且接受string参数的方法。我们将方法赋值给委托实例,并通过委托调用该方法。

qq_45728381的博客 1543

C#中的事件委托

委托 事件 委托与事件的关系和运用

nexttoparadise的博客 1051

C#中的委托与事件笔记——基础

学习笔记内容来自B站UP主十月的寒流,内容仅作学习记录

WDaMu的博客 795

C#中的委托、事件与接口

简述委托、事件与接口

Z_hongli的博客 1559

C#委托与事件的总结

这两天学习C#的委托、事件,看的我是云里雾里,还好看了几个例,总算是基本上弄懂了。在网上看到了一篇总结委托与事件的文章,写的很基础,很容易懂。文章来源:http://www.cnblogs.com/cloudjun/archive/2006/10/07/250931.html文章如下:c#委托与事件 心得 c#用委托来实现事件通知机制。委托相当与c++函数指针。整个过程涉及一个呼叫

月夏的专栏 928
上一篇: C#中的委托与事件笔记——基础
WDaMu
博客等级 码龄4年 27粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值