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

数字锁相环的原理与FPGA实现

数字锁相环是锁相环电路的全数字实现。锁相环电路能够实现对输入信号的相位进行跟踪,进而在噪声中提取纯净的有用信号。以上就是今天要讲的内容,本文简单地介绍了锁相环的原理,然后,在Vivado仿真平台上,通过verilog做仿真验证。最终仿真结果能够实现锁定,但锁定时间较长,表明参数仍可做调整。

weixin_45857378的博客 8510

老服务器焕新记:在Dell R730上折腾Nvidia K80显卡的完整记录(含Anaconda环境配置)

本文详细记录了在Dell R730服务器上为Nvidia K80计算卡安装驱动、配置CUDA及Anaconda环境的完整过程。文章重点解决了老旧硬件与CentOS 7系统的兼容性问题,提供了从BIOS设置、驱动版本精准匹配到Python机器学习环境搭建的实战指南,旨在帮助读者低成本挖掘旧服务器的GPU计算潜力。

weixin_29197835的博客 504

C#中委托和事件

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

andu1644的博客 1万+

GD32F103程序烧录全攻略:从SWD到串口的实战指南

本文提供了GD32F103微控制器程序烧录的全面实战指南,详细介绍了SWD、JTAG和串口(ISP)三种主流下载方式。文章重点解析了在Keil MDK中使用ST-Link进行SWD下载的完整步骤,包括硬件连接、软件配置和Flash算法设置,并针对烧录过程中的常见问题提供了实用的排坑解决方案,帮助开发者高效完成程序部署。

weixin_29191669的博客 438

c# 中的事件与委托详解

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

qq_39024280的博客 6244

Dify工作流构建案例:迭代驱动的多维深度搜索

为了克服这些挑战,我们可以设计一个能够智能协同内部知识库与外部互联网搜索,并最终由大型语言模型(LLM)进行深度整合与精准回答的高级工作流。

同名公众号:dify实验室 2292

Unity-TextMeshPro如何扩展材质实现字体Face+Outline流光效果

前言 TexeMeshPro 是Unity的一个Text文本插件,实现了比UGUI的Text,更好看的效果,跟高效的性能,所以深受大家的喜欢,但是再好的插件,也不是万能的,比如我们的策划有个新需求,要我们的VIP的名字比普通玩家有更好看的效果,例如:字体流光,外发光颜色扰动,字体贴图等等。那我们就需要去扩展TextMeshPRo的shader功能了。如下图所示 本文,我就带大家一起来扩展一下:如何扩展TextMeshProUGUI TextMesh原始面板 扩展功能后的面板 扩展TextMeshPro

TxNet 9677

C# 委托与事件总结

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

萌宅鹿的技术小屋 2617

STM32 HAL PWM (占空比) -电机软启动不到位解决

为了避免电机启动电压大造成设备损坏,或者供电不足导致重启,通常在对启动都需要一个PWM进行软启动,下面对PWM电机软启动详细介绍。

weixin_44597885的博客 867

C#中的委托和事件

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

weixin_73376914的博客 2349

Open3D 使用RANSAC分割平面【2026最新版】

使用RANSAC从点云中分割平面,用segement_plane函数。博客长期更新,本文最新更新时间为:2026年2月28日。

点云侠的博客 37万+

TC3XX - MCAL知识点(三十九):AURIX™ TC3xx 的EDSADC实现旋变解码功能(应用笔记记录)

本文总结了英飞凌应用笔记中关于EDSADC旋变解码系统的关键内容。系统通过调幅解调获取电机位置和速度信号,支持内外载波生成方案,其中内部载波方案更常用(需2个DSADC通道)。重点介绍了滤波器链配置建议(避免FIR1)、系统条件要求(如偶数积分周期)以及群延迟计算方法。特别分析了SDCAP功能对硬件延迟的补偿机制,指出温度等因素可能导致外部电路延迟变化,需通过计数器测量并通过软件调整积分器起始点来消除角度误差。文中还提供了不同硬件延迟情况下的信号处理示例。

梦想技术家 462

C# 之委托与事件详解

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

weixin_45590420的博客 1920

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

理解 C# 中的委托与事件

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

2401_85253577的博客 906

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

C#委托与事件

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

布小禅的博客 2378

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

掌握 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、付费专栏及课程。

余额充值