dotnet 委托的实现解析

dotnet 委托的实现解析(2)开放委托和封闭委托 (Open Delegates vs. Closed Delegates) Python微信订餐小程序课程视频 https://edu.youkuaiyun.com/course/detail/36074 Python实战量化交易理财系统 https://edu.youkuaiyun.com/course/detail/35475 前言 这是个人对委托的理解系列第二篇,部分翻译自 Open Delegates vs. Closed Delegates – SLaks.Blog,好像还没人翻译过,加上部分个人理解。希望能对大家理解委托有所帮助。 正文 .Net支持两种委托:开放委托和封闭委托。open de 阅读详情

Python微信订餐小程序课程视频

https://edu.youkuaiyun.com/course/detail/36074

Python实战量化交易理财系统

https://edu.youkuaiyun.com/course/detail/35475

缘起

最近被问到什么是.Net中的委托。问题虽然简单却无从回答。只能说委托是托管世界的函数指针,这么说没啥大毛病,但也都是毛病(当时自己也知道这么说不太对,不过自己不太爱用这个也没准备确实没有更好的答案)。

执行效率

正巧前段时间看Core CLR的文档看到不同方式调用函数效率的比较正巧有这个,摘录如下。这段内容在 clr官方文档
的 为什么反射很慢 ?里。

Reading a Property (‘Get’)

MethodMeanStdErrScaledBytes Allocated/Op
GetViaProperty0.2159 ns0.0047 ns1.000.00
GetViaDelegate1.8903 ns0.0082 ns8.820.00
GetViaILEmit2.9236 ns0.0067 ns13.640.00
GetViaCompiledExpressionTrees12.3623 ns0.0200 ns57.650.00
GetViaFastMember35.9199 ns0.0528 ns167.520.00
GetViaReflectionWithCaching125.3878 ns0.2017 ns584.780.00
GetViaReflection197.9258 ns0.2704 ns923.080.01
GetViaDelegateDynamicInvoke842.9131 ns1.2649 ns3,931.17419.04

Writing a Property (‘Set’)

MethodMeanStdErrScaledBytes Allocated/Op
SetViaProperty1.4043 ns0.0200 ns6.550.00
SetViaDelegate2.8215 ns0.0078 ns13.160.00
SetViaILEmit2.8226 ns0.0061 ns13.160.00
SetViaCompiledExpressionTrees10.7329 ns0.0221 ns50.060.00
SetViaFastMember36.6210 ns0.0393 ns170.790.00
SetViaReflectionWithCaching214.4321 ns0.3122 ns1,000.0798.49
SetViaReflection287.1039 ns0.3288 ns1,338.99115.63
SetViaDelegateDynamicInvoke922.4618 ns2.9192 ns4,302.17390.99

上表分别列出了读取和设置属性通过不同方式的耗时等结果,我们可以看到直接通过属性读取和通过委托读取速度的平均值相差了接近10倍。这么看委托显然就不是函数指针了(函数指针的性能损失很小),那么下面就具体看下究竟是啥。

解析

先上实例代码如下:

    internal class HelloWorld
    {
        public static void HelloWorld1()
        {
            Console.WriteLine("hello world1");
        }

        public delegate void SayHi();

        public void Main()
        {
            SayHi? helloWorld = new SayHi(HelloWorld1);
            helloWorld.Invoke();
        }
    }

很简单的代码,编译后用ILSpy打开。

元数据与IL

首先看下元数据表,毫不例外的在02 TypeDef表里找到了委托对象类型定义,毕竟一切皆对象,这个应该和事件是一个处理方法。

NameBaseTypeFieldListMethodList
SayHi0x100000E0x40000000x600006

剩下的表暂时先不看了(主要时间太长不记得类型方法在表里是咋对应起来的了)

下面先把类型SayHi的定义相关的IL代码贴出来

.class nested public auto ansi sealed SayHi
    extends [System.Runtime]System.MulticastDelegate
{
    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor (
            object 'object',
            native int 'method'
        ) runtime managed 
    {
    } // end of method SayHi::.ctor

    .method public hidebysig newslot virtual 
        instance void Invoke () runtime managed 
    {
    } // end of method SayHi::Invoke

    .method public hidebysig newslot virtual 
        instance class [System.Runtime]System.IAsyncResult BeginInvoke (
            class [System.Runtime]System.AsyncCallback callback,
            object 'object'
        ) runtime managed 
    {
    } // end of method SayHi::BeginInvoke

    .method public hidebysig newslot virtual 
        instance void EndInvoke (
            class [System.Runtime]System.IAsyncResult result
        ) runtime managed 
    {
    } // end of method SayHi::EndInvoke

} // end of class SayHi


这里第一个意外出来了,我一直以为委托是继承自System.Delegate但是没想到却是继承自System.MulticastDelegate。大家都知道后者继承前者主要就是是为了实现 += 这种多播委托的方式(也就是天天写事件用的这种方式)。 那么委托像事件那么注册好多个就是合情又合理了。也就是如下这种。

    internal class HelloWorld
    {
        public static void HelloWorld1()
        {
            Console.WriteLine("hello world1");
        }

        public static void HelloWorld2()
        {
            Console.WriteLine("hello world2");
        }

        public delegate void SayHi();

        public void Main()
        {
            SayHi? helloWorld = new SayHi(HelloWorld1);
            helloWorld += HelloWorld2;
            helloWorld.Invoke();
        }
    }

果然是可以的,可惜大家(我们组的其他同事)宁愿用事件的方式,从来没见这么用过。
IL里定义的其他方法也没啥稀奇的Invoke这类的都是编译器加进去的,直接调用clr里处理,这里看不到实现。

小小的结论与一些疑惑

先说结论: (大胆猜测:)委托实际上和事件类似都是编译成一个对象,然后JIT执行到这个stub时再以FCall的形式(也许是QCall(FQ傻傻分不清),毕竟是动态生成的类不是很了解)调用到CLR里。我不爱用这个果然是对的。

再说说疑惑:
实际上最近在混合调试托管代码时遇到了很大问题。也就是

  • 只调试托管代码或者System.Private.CoreLib时没有问题。
  • 只调试core clr时也没问题(虽然大部分看不懂)。
  • 一旦混合调试时(托管代码调用clr的功能如 GetHashcode 或者 lock时)就有很多函数进不去,但是也不是也不是完全进不去,还是可以看见一部分混合调用的堆栈的。导致我现在很多只能靠猜,例如GetHashcode()是以FCall的形式调用到CLR里,直接在Core CLR里相关的代码打断点就能进入断点。

希望有缘人解答一下,我已经按clr的官方文档处理了,现在只剩下无奈与黔驴技穷了。
当然文中的其他问题也希望有缘人不吝指出。感谢。

小甲鱼python视频xxoo爬虫代码改进--煎蛋网 2020/7/31 今天学习得是关于小甲鱼得python课程,根据这个课程也确确实实得学到了不少东西,所以希望大家也可以一起去学习 下面是我在小甲鱼上课改造之后得代码 这个课程是在b站上看的,号码是 av27789609 这个是第五十节左右得爬虫 ooxx 他的教学视频是很早的时候录得,现在的网站进行了base64的加密等反爬措施,所以在原有的基础上需要进行修改 下面是我的代码,希望可以给大家一些启发,同时也希望大佬们给与指点。 import urllib.request import urllib 阅读详情

相关推荐

C#委托本质解析:从IL指令到内存泄漏避坑指南

委托是.NET中类型安全的函数对象,其底层基于MulticastDelegate运行时契约,通过ldftn指令加载本机方法地址并绑定target实例。理解委托即理解CLR如何管理方法引用、闭包捕获与多播调用链,这对规避内存泄漏、线程死锁和性能抖动至关重要。技术价值体现在事件模型解耦、异步回调编排及插件化扩展能力;典型场景覆盖WinForms/WPF事件绑定、后台任务调度、消息总线设计及AOT编译适配。尤其需警惕闭包延长对象生命周期与多播委托数组重排开销——这正是C#委托在高并发系统中引发吞吐量暴跌的核心根因

diedangxiang4092的博客 385

超碰网站源码搭建教程超碰在线视频搭建超碰网站搭建教程

超碰网站源码搭建教程超碰在线视频搭建超碰网站搭建教程

u011167460的专栏 610万+

C#文字修仙游戏源码解析:数值驱动架构与核心系统实现

在游戏开发中,数值驱动架构通过数据配置与状态管理实现动态平衡,其核心原理是将游戏逻辑与数值解耦,提升可维护性与扩展性。C#凭借强类型和面向对象特性,适合构建此类系统。技术价值在于支持复杂成长模型与随机判定,应用场景包括文字修仙、RPG等。本文以基于C#的文字修仙游戏源码为例,深入剖析境界状态机、灵根功法加成计算及随机数种子控制等关键实现,展示如何用清晰类结构驱动长周期修仙成长。

weixin_28040125的博客 57

委托

委托是用于方法赋值 应用 UI层和其他层的交互 在一些特定的场景中需要将方法注入到其他里面去执行 使用方法 定义目标方法 定义委托类型 委托和目标方法基本一致 申明委托变量 变量赋值 执行委托 using System; namespace 委托 { //2 定义委托类型 委托和目标方法基本一致 public delegate void DelegateEat(); ...

luxifa1的博客 287

C# 入门实战:从环境搭建到面向对象与通信开发

C# 是构建在 .NET 平台上的强类型面向对象编程语言,其核心机制包括值类型与引用类型的内存模型、委托与事件驱动模型以及泛型集合的动态管理。理解这些基础原理,有助于开发者编写类型安全、可维护性高的代码,尤其在需要处理异步通信、数据持久化和界面交互的工程场景中价值显著。例如,上位机开发常通过 TcpListener 接收多客户端数据,利用委托与事件解耦通信与界面刷新,同时借助 Dapper 简化数据库读写。掌握 C# 语言骨架、开发环境配置、面向对象写法、集合与字符串处理以及调试排错,是独立完成控制台工具、

weixin_31421613的博客 230

深度解析 DotNet 公用类库:源码+文档+实例

本文还有配套的精品资源,点击获取 简介:公共类库在软件开发中至关重要,通过提供功能模块来提升开发效率。本文以"DotNet公用类"为例,深入分析其源码,详细解读相关文档,并通过实例演示如何应用。介绍类与接口、静态类、扩展方法的设计原理,以及API参考、示例代码的重要性。通过日常任务、数据验证和数据转换的实例应用,展示了类库在实际开发中的实用性。 1. 公共类库在软...

weixin_35995661的博客 1025

01 windows10下node、python、dotnet、php版本切换指南

安装时会自动创建环境变量NVM_HOME 和NVM_SYMLINK并配置到path。

qq_42574478的博客 344

PythonDotNet:各种编译的 PythonDotNet 版本

用于 .NET 的 Python 这个存储库包含一些优秀的 Python for .NET 库的编译版本 - 官方版本可以从下载 2014年 12 月更新- 官方项目现已在 GitHub 上提供,为 Python for .NET 是一个包,它使 Python 程序员几乎可以与 .NET 公共语言运行时 (CLR) 无缝集成,并为 .NET 开发人员提供强大的应用程序脚本工具。 使用此包,您可以编写 .NET 应用程序脚本或使用 Python 构建整个应用程序,使用以任何面向 CLR(托管 C++、C#、VB、JScript)的语言编写的 .NET 服务和组件。 目前可用 以下版本目前可用。 /PythonDotNet202_py27_net4_x64_Windows2012 适用于 .NET v2.0.2 的 Python 64 位 DLL 为 .NET 4.0 框架构建

dotnet 手动解决 json 解析中不合法字符串

如果使用 Newtonsoft Json 解析字符串,字符串里面有不清真的格式,那么默认的解析将会炸掉。如果想要自己解决字符串中的不清真格式,可以使用传入 JsonSerializerSettings 的方法 我写了一段字符串,里面需要解析为日期请看代码 @"[ '2009-09-09T00:00:00Z', '这是歪楼的', [ 1 ...

lindexi 766

run-python-from-dotnet:执行python脚本并捕获其输出

run-python-from-dotnet:执行python脚本并捕获其输出

【架构设计】DDD 到底解决了什么问题

DDD作为架构设计思想帮助微服务控制规模复杂度,那它是怎么做到的呢?第一章提出了架构的根本目是解决系统复杂度,并简要说明系统复杂度的六个来源及通用解法,为我们设计架构提供了清晰可执行的操作思路。

DreamSun的博客 1162

深入解析dotnet 事件和委托

  对.net事件的看法   (这是本文在博客园的地址,请到此地下在代码)一、事件的本质事件是软件系统里的两个子系统之间,或者两个模块之间,或者两个对象之间发送消息,并处理消息的过程。在面向对象的世界里,就可以统一认为是两个对象之间的行为。两个对象之间发送的这种消息,对发送方来讲是产生一个事件,对接受方来讲是需要处理某个事件。这种消息可以是用户操作产生的或者软件系统里的某个对象产生的。

worldreason的专栏 496

硬件设计--DC/DC电源芯片详解

本文参考:http://www.elecfans.com/article/83/116/2018/20180207631874.html https://blog.youkuaiyun.com/wangdapao12138/article/details/79763343 第一次写博客,不喜勿喷,谢谢!!! DC/DC电源指直流转换为直流的电源,从这个定义上看,LDO(低压差线性稳压器)芯片也应该属于D...

weixin_30794499的博客 7877

firebase-database-dotnet源码解析:核心组件设计与实现原理

firebase-database-dotnet是一个专为Firebase Realtime Database打造的C#库,它提供了高效的数据同步、离线支持和查询功能,帮助开发者轻松构建实时应用。本文将深入解析其核心组件的设计思路与实现原理,带你了解这个强大工具的内部工作机制。 ## 核心组件概览 该库采用模块化设计,主要包含四大核心组件,它们协同工作以实现与Firebase Realtime

gitblog_00484的博客 143

Ubuntu使用gstreamer开发USB相机应用(一)

Ubuntu使用gstreamer开发USB相机应用(一) 包括:gstreamer安装,测试。使用v4l2测试USB相机。使用gstreamer采集相机

Alon1787的博客 2739

UMI刷盘机器人代码实战:从SLAM到Diffusion Policy的完整部署流程

本文详细解析了UMI(Universal Manipulation Interface)刷盘机器人从数据准备到真实部署的完整实战流程。通过SLAM处理视频数据生成三维轨迹,并训练Diffusion Policy模型,最终将策略部署到UR5机械臂与WSG50夹爪上,实现从模仿学习到物理执行的闭环。

weixin_29042035的博客 461

.Net中的委托与事件(DelegateEvent)

委托 委托的简单运用 一个委托类型定义了该类型的实例能调用的一类方法,这些方法含有同样的返回类型和同样的参数(形参和个数相同)。委托和接口一样,可以定义在类的外部。如下定义的一个委托类型 - Calculator: delegate int Calculator (int x); 此委托适用任何有着 int 返回类型和一个 int 类型参数的方法、如: static int Double ...

weixin_43965881的博客 1023

超详细YOLOv8姿态检测全程概述:环境、训练、验证与预测详解

本篇博客详细介绍了使用YOLOv8-pose进行姿态估计的全过程,包括不同版本模型的性能比较、训练与验证步骤,以及预测代码的实现。它对模型参数、训练过程和输出结果进行了解释,同时提供了详细的配置文件示例和标签数据格式说明。此外,还演示了如何使用预训练模型进行图像预测,并如何处理和理解预测结果。最后,它还讨论了如何评估和比较不同模型的性能。如果有哪里写的不够清晰,小伙伴本可以给评论或者留言,我这边会尽快的优化博文内容,另外如有需要,我这边可支持技术答疑与支持。

CDBmax的博客 3万+

关于DotNET的整理

继整理C/C++学习笔记后,blog好久都没有文章更新了.最近准备抽空把关于DotNET和Linux的相关笔记陆续整理上传做网上备份。内容为一年前整理的资料,非实际项目代码或设计框架,仅为表现某知识点或思想,故代码结构离实际应用有差异。各公司要求开发标准也不尽相同,想学习标准项目框架者以M$的pet shop为准。 如此,如某些文章内容对您有用欢迎任意使用或转载。转载前请注意内容来源,转...

weixin_33962621的博客 284

STM32F103单片机驱动TM1637数码管显示模块

最近项目中需要用到数码管显示,于是买了一个TM1637芯片驱动的四位数码显示模块,现将调试过程记录一下,方便以后参考。 使用的单片机是STM32F103C8T6最小系统 使用的数码管模块是TM1637四位数码管显示模块 实际运行效果 下面先看一下TM1637和数码管连接的具体线路图 实际使用的模块没有带按键,只用了4个数码管,模块和单片机连接只需要4根线VCC、GND、CLK、DIO。芯片和单片机通信使用的是I2C总线,下面就来说一下如何...

HXYDJ的博客 1万+

PX4从放弃到精通(二十七):固定翼姿态控制

固件版本 PX4 1.13.2欢迎交流学习,可加左侧名片。

超维空间科技的博客 6892

Vlc.DotNet核心组件解析:从VlcControl到VlcMediaPlayer的全面探秘

Vlc.DotNet是一个强大的.NET控件,它封装了VLC库的音视频功能,为开发者提供了在.NET应用中集成高质量媒体播放的能力。本文将深入解析Vlc.DotNet的核心组件,从高层的VlcControl到底层的VlcMediaPlayer,帮助开发者全面了解这个库的架构和使用方法。 ## 核心组件概览 Vlc.DotNet的核心架构采用了分层设计,主要包含以下几个关键组件: - **Vl

gitblog_00704的博客 374

uniapp - 实现 App 端 “半屏幕“ 连续扫码功能,页面只有半个屏幕是扫码框并且可持续连续扫码获取数据(不使用官方 uni.scanCode API,因为无法连续扫码!)详细示例源码插件教程

uniapp app端实现半屏幕扫码,uniapp 扫一扫半个屏幕,uniapp 扫一扫,uniapp持续扫码实现,uniapp怎么自定义扫码和连续扫码,uni-app App端半屏连续扫码,uniapp 扫一扫半个屏幕,uniapp自定义扫码页面样式,实现连续扫码功能(uniapp),uniapp - 实现 App 端 "半屏幕" 连续扫码功能,页面只有半个屏幕是扫码框并且可持续连续扫码获取数据(不使用官方 uni.scanCode API,因为无法连续扫码!)详细示例源码插件教程。

✅ 精选推荐文章 1万+

C#中的委托和事件

DotNet规范的委托和事件写法: public delegate void EventHandler(object sender, EventArgs e); //定义委托类型 public event EventHandler Click; //声明事件类似于声明了一个封装的委托变量 this.btnOpenDB.Click += new System.EventHandle...

weixin_34365635的博客 77

蓝牙模块HM-10手册

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

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

LangChain for Beginners Few-Shot 提示实战:用 3 个示例教会 AI 按你的格式写作

在 langchain-for-beginners 课程中,**Few-Shot Prompting(少样本提示)** 被公认为最实用的提示工程技巧之一。它的思路很简单:与其用一大段文字描述你想要的格式,不如直接给 AI 看 3 个「输入 → 输出」示例,让它自己总结出规律。这篇文章将带你从零理解 Few-Shot 提示的原理、在 LangChain 中的实现方式,以及如何用它教会 AI 稳定输出

gitblog_00056的博客 765

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

DotNetIsolator架构完全解析:Wasmtime、dotnet-wasi-sdk与Mono如何协同工作

DotNetIsolator 是一个让你在 .NET 进程中"套娃"运行另一个 .NET 运行时(Runtime)的实验性开源库,核心架构解析在于把 WebAssembly 沙箱、编译工具链与 Mono 运行时三者巧妙地拼装在一起。读完本文,你会彻底搞懂:为什么一个 WebAssembly 模块里能跑完整的 .NET 代码、宿主与沙箱之间的方法调用是如何穿越边界的、以及 Wasmtime、dotn

gitblog_07497的博客 350

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: Linux常用命令
下一篇: CSS自定义属性与前端页面的主题切换
pythonxxoo
博客等级 码龄5年 337粉丝 670原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值