C#委托详解

发布时间:2026/10/23 2:53:40

C#委托详解 什么是委托Action泛型委托Delegate用来封装一个方法且方法不具有参数与返回值Func泛型委托Delegate用来表示一个有返回值的方法尖括号最后一个类型是返回值前面的是参数class Program { static void Main(string[] args) { Calculator calculator new Calculator(); Action action new Action(calculator.Report); calculator.Report(); //直接调用 action(); //间接调用 action.Invoke(); //间接调用同action(); Funcint, int, int func1 new Funcint, int, int(calculator.Add); Funcint, int, int func2 new Funcint, int, int(calculator.Sub); int x 100; int y 200; int z 0; z func1(x, y); //同z func1.Invoke(x, y); Console.WriteLine(z); z func2(x, y); Console.WriteLine(z); } } class Calculator { public void Report() { Console.WriteLine(I hava 3 methods.); } public int Add(int a, int b) { int result a b; return result; } public int Sub(int a, int b) { int result a - b; return result; } }委托的声明自定义委托一般的类声明class 类名 { 类体 }委托的声明放在namespace下是最标准、最清晰的写法放在 类 下则变成嵌套类public delegate double Calc(double x, double y);public-公开访问delegate-关键字告诉编译器我要声明委托了double-目标方法的返回值类型Calc-委托名()-目标方法的参数列表加了括号()代表“立刻执行这个方法并拿到结果”不加括号代表“把这个方法本身当作一个对象传递出去”。Calc calc1 new Calc(calculator.Add);与Calc calc1 new Calc(calculator.Add());使用委托的方法①声明委托②创建委托的实例并将目标方法名称放入委托构造函数的参数列表里③执行委托实例的方法例如Action.Invoke()或者直接用简写Action()则可以通过委托实例的方法来间接调用目标方法namespace ConsoleHelloWorld { public delegate double Calc(double x, double y);//声明委托 class Program { static void Main(string[] args) { Calculator calculator new Calculator(); Calc calc1 new Calc(calculator.Add); Calc calc2 new Calc(calculator.Sub); Calc calc3 new Calc(calculator.Mul); Calc calc4 new Calc(calculator.Div); double a 100; double b 200; double c 0; c calc1(a, b); Console.WriteLine(c); c calc2(a, b); Console.WriteLine(c); c calc3(a, b); Console.WriteLine(c); c calc4(a, b); Console.WriteLine(c); } } class Calculator { public double Add(double x, double y) { return x y; } public double Sub(double x, double y) { return x - y; } public double Mul(double x, double y) { return x * y; } public double Div(double x, double y) { return x / y; } } }委托的使用委托的一般使用日常使用模板方法日常使用委托时一般把委托当作方法的参数传入方法中①实现方法委托封装了方法1然后将该委托当作参数传给方法2②好处简介可以将可能产生变化的业务逻辑部分放在方法1中而方法2当作一个“模板”即模板方法通过固定的委托间接调用方法1这样当业务逻辑需求发生变化时就不用该方法2的代码了而只需要改方法1的代码甚至直接将委托中封装的方法换一个以实现其它功能填空题class Program { static void Main(string[] args) { ProductFactory productFactory new ProductFactory(); //生产产品 WrapFactory wrapFactory new WrapFactory(); //打包产品 FuncProduct func1 new FuncProduct(productFactory.MakePizza); FuncProduct func2 new FuncProduct(productFactory.MakeToyCar); Box box1wrapFactory.WrapProduct(func1); Box box2 wrapFactory.WrapProduct(func2); Console.WriteLine(box1.Product.Name); Console.WriteLine(box2.Product.Name); } } class Product //每个产品有自己的名字 { public string Name { get; set; } } class Box //箱子里装的东西 { public Product Product { get; set; } } class WrapFactory //打包工厂模板方法 { public Box WrapProduct(FuncProduct getProduct) { Box box new Box(); // 1. 先拿个空箱子 Product product getProduct();// 2. 调用委托拿到产品唯一变的填空题的空 box.Product product; // 3. 把产品装进箱子里 return box; // 4. 把装好的箱子交出去 } } class ProductFactory //产品生产厂 { public Product MakePizza() { Product product new Product(); product.Name Pizza; return product; } public Product MakeToyCar() { Product product new Product(); product.Name Toy Car; return product; } }回调方法可以调用也可以不调用用得着的时候就调用用不着就不调用可以动态的选择后续将被调用的方法。如A给B一张名片告诉B有需要可以打电话给A同时又有C、D等也给B名片B可以动态的选择后续需要谁的帮忙。把委托类型的参数传到主调方法里被传进主调方法的委托类型的参数内部会封装被回调的方法主调函数根据自己的逻辑来确认要不要调用回调方法。回调方法常位于主调函数末尾无返回值。namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { ProductFactory productFactory new ProductFactory(); //生产产品 WrapFactory wrapFactory new WrapFactory(); //打包产品 FuncProduct func1 new FuncProduct(productFactory.MakePizza); FuncProduct func2 new FuncProduct(productFactory.MakeToyCar); Logger logger new Logger(); ActionProduct log new ActionProduct(logger.Log); Box box1wrapFactory.WrapProduct(func1,log); Box box2 wrapFactory.WrapProduct(func2, log); Console.WriteLine(box1.Product.Name); Console.WriteLine(box2.Product.Name); } } class Logger //日志 { public void Log(Product product) { //不带时区的UtcNow Console.WriteLine(Product {0} created at {1}.Price is {2}.,product.Name,DateTime.UtcNow,product.Price); } } class Product //每个产品有自己的名字 { public string Name { get; set; } public double Price { get; set; } } class Box //箱子里装的东西 { public Product Product { get; set; } } class WrapFactory //打包工厂模板方法 { public Box WrapProduct(FuncProduct getProduct,ActionProduct logCallback) { Box box new Box(); // 1. 先拿个空箱子 Product product getProduct();// 2. 调用委托拿到产品唯一变的填空题的空 if (product.Price 50) { logCallback(product); } box.Product product; // 3. 把产品装进箱子里 return box; // 4. 把装好的箱子交出去 } } class ProductFactory //产品生产厂 { public Product MakePizza() { Product product new Product(); product.Name Pizza; product.Price 12; return product; } public Product MakeToyCar() { Product product new Product(); product.Name Toy Car; product.Price 100; return product; } } }委托的高级使用单播委托1个委托封装1个方法。using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Action action1 new Action(stu1.DoHomework); Action action2 new Action(stu2.DoHomework); Action action3 new Action(stu3.DoHomework); action1(); //action.Invoke(); action2(); action3(); } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }多播委托1个委托中封装着不止1个方法多播委托在调用的时候它执行的顺序是按照封装方法的先后顺序来执行的using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Action action1 new Action(stu1.DoHomework); Action action2 new Action(stu2.DoHomework); Action action3 new Action(stu3.DoHomework); action1 action2; //多播委托 action1 action3; action1(); } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }第一个运行起来的线程就是进程的主线程其他线程叫做分支线程。同步调用单线程调用在同一个线程内调用方法时方法的执行时前一个执行完后一个才执行在同一个线程内依次执行的方法调用叫做同步调用直接同步调用using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; stu1.DoHomework(); stu2.DoHomework(); stu3.DoHomework(); for (int i 0; i 10; i) //回到主线程 { Console.ForegroundColor ConsoleColor.Cyan; Console.WriteLine(Main thread {0},i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }单播委托的间接同步调用using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Action action1 new Action(stu1.DoHomework); Action action2 new Action(stu2.DoHomework); Action action3 new Action(stu3.DoHomework); action1(); action2(); action3(); for (int i 0; i 10; i) //回到主线程 { Console.ForegroundColor ConsoleColor.Cyan; Console.WriteLine(Main thread {0}, i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }多播委托的间接同步调用异步调用多线程调用在不同的线程中去调用方法每个线程跟另外一个线程都互不相干指的是逻辑上互不相干现实工作中经常会遇到多个线程共享同时访问同一个资源比如某个变量的情况 这时候如果处理不当就会产生线程间争夺资源的冲突一个线程的开始和结束并不会影响另一个线程的开始和结束。隐式异步调用begininvoke自动生成分支线程去调用封装的方法using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Action action1 new Action(stu1.DoHomework); Action action2 new Action(stu2.DoHomework); Action action3 new Action(stu3.DoHomework); action1.BeginInvoke(null, null); action2.BeginInvoke(null, null); action3.BeginInvoke(null, null); //都在争抢控制台前景色资源导致冲突 //为避免冲突后续会为线程加锁 for (int i 0; i 10; i) //回到主线程 { Console.ForegroundColor ConsoleColor.Cyan; Console.WriteLine(Main thread {0}, i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }主线程与分支线程谁也不等谁同时执行显式异步调用自己动手生成多线程using System; using System.Threading; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Action action1 new Action(stu1.DoHomework); Action action2 new Action(stu2.DoHomework); Action action3 new Action(stu3.DoHomework); Thread thread1 new Thread(new ThreadStart(stu1.DoHomework)); Thread thread2 new Thread(new ThreadStart(stu2.DoHomework)); Thread thread3 new Thread(new ThreadStart(stu3.DoHomework)); thread1.Start(); thread2.Start(); thread3.Start(); for (int i 0; i 10; i) //回到主线程 { Console.ForegroundColor ConsoleColor.Cyan; Console.WriteLine(Main thread {0}, i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleHelloWorld { class Program { static void Main(string[] args) { Student stu1 new Student() { ID 1, PenColor ConsoleColor.Yellow }; Student stu2 new Student() { ID 2, PenColor ConsoleColor.Green }; Student stu3 new Student() { ID 3, PenColor ConsoleColor.Red }; Task task1 new Task(new Action(stu1.DoHomework)); Task task2 new Task(new Action(stu2.DoHomework)); Task task3 new Task(new Action(stu3.DoHomework)); task1.Start(); task2.Start(); task3.Start(); for (int i 0; i 10; i) //回到主线程 { Console.ForegroundColor ConsoleColor.Cyan; Console.WriteLine(Main thread {0}, i); Thread.Sleep(1000); } } } class Student { public int ID { get; set; } public ConsoleColor PenColor { get; set; } //输出时的颜色 public void DoHomework() { for (int i 0; i 5; i) { Console.ForegroundColor this.PenColor; //控制台字符颜色 Console.WriteLine(Student {0} doing homework {1} hour(s)., this.ID, i); Thread.Sleep(1000); //线程休眠1000ms1s } } } }*用类声明一个类类型的属性/字段和用类创建一个类实例的区别是什么本质上是一样的用类创建一个实例赋值左边的就是先声明了一个类类型的变量其实也可以看做是一个字段字段就是一种变量
延伸阅读

更多相关文章

2026/10/23 2:53:40

PFM 升压型五节电池充电管理集成电路CN3325

概述:CN3325是一款PFM升压型五节锂电池充电管理集成电路。 CN3325采用涓流,恒流和准恒压模式(Quasi-CVTM )对五节锂电池进行充电管理,内部集成有基准电压源,电感电流检测单元,控制电路和片外场效应晶体管驱动电路等&am…

2026/10/23 2:53:40

FA_CNN卷积神经网络十二_CIFAR10全流程PyTorch

FA:Formulas and Algorithm,CNN:Convolutional Neural Network 1. 项目概述 本文基于 PyTorch 框架,使用经典的 CIFAR10 数据集,完整演示一个图像分类模型的训练与验证流程。内容涵盖: 使用 GPU 加速训练一…

2026/10/23 2:53:40

PTFE高频覆铜板制造能力评估:从参数、工艺到数据核验

PTFE覆铜板在高频PCB中的价值通常由Dk/Df规格书体现,但材料参数本身并不保证制造可行性。PTFE的表面能、CTE和力学特性使它在孔金属化、钻孔、去钻污和混压环节引入若干可测量的工艺风险。本文不以“选型推荐”为目标,而是把公开标准、工艺文献和专利中出…

2026/10/23 6:09:02

RISC-V IDE MRS进阶分享(三):MRS语言服务器

RISC-V IDE MRS进阶分享(三):MRS语言服务器 MounRiver Studio (MRS )的语言服务器是基于clangd的改进版本,可为 C、C等语言开发提供实时的语法分析、智能补全、代码导航、错误诊断、代码重构等功能。下面以沁恒的CH32V317模板工程…

2026/10/23 6:09:02

【kali渗透测试】内网横向渗透横向移动基础

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 6:09:02

具身智能系统概论——感知系统

本章系统阐述了具身智能的多模态感知体系。视觉方面,RGB-D相机实现立体感知,事件相机以微秒级响应捕捉动态,占用网络则通过3D空间占据概率统一表征环境,支持遮挡处理与多模态融合。触觉与本体感觉依托力矩传感器、IMU与电子皮肤&a…

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/23 0:02:26

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

2026/10/23 0:02:26

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

2026/10/23 0:02:26

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑