C# 委托详解(Delegate)

2024-08-28 20:44

本文主要是介绍C# 委托详解(Delegate),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

在 C# 编程当中,委托(Delegate)是一种特殊的类型,它允许将方法作为参数传递给其他方法,或者将方法作为返回值返回,这种特性使得委托成为实现回调函数、事件处理等,所有的委托都派生自System.Delegate类。

C#中的委托类似于C 或 C++中函数的指针。委托是存在对某个方法的引用的一种引用类型变量,引用可以在运行的时候被打断,当事件出现,就必然有委托的影子,而有委托的时候却不一定会有事件出现。


委托的概念

委托是一种引用类型变量,存储某一个方法的内存地址

委托的格式

public delegate 返回值类型 MyDelegate();
//这里面的Mydelegate就是一个委托类型

委托的使用步骤

  1. 声明一个委托(函数指针)
  2. 创建委托对象
  3. 创造符合委托格式的函数。(指针指向的函数)
  4. 将函数名称赋值给委托。

这里举个例子吧:

using System;
namespace 练习
{internal class Program{public delegate int Count(int a, int b);public static int Add(int a, int b){return a + b;}static void Main(string[] args){Count c1 = new Count(Add);int c = c1(1, 2);Console.WriteLine(c);Console.Read();}}
}

在这串代码里面 定义了一个名为 "Count"委托类型,这里 Count 可以引用任何接收两个int参数并且返回一个 int 的方法

定义了一个名为 "Add" 的静态方法,它接受了两个 int 参数并且返回它们的和

在Main方法里面,创建了一个Count类型的委托实例 c1 ,并将其初始化引用为 Add 方法,并传入了这两个参数

调用委托 c1,传入两个参数1和2,由于委托引用 Add 方法,所以这行代码实际上调用了Add方法,并传入了这两个参数

小贴士

        使用委托时,我们一般采用两种情况

  1. 直接调用委托变量,就像刚才例子里面的那样
  2. 使用 invoke() ,简单就直接上代码例子:

委托的用处(配有代码例子)

  • 回调:

委托是实现回调的基础,它允许程序将一个方法(或函数)作为参数传递给另一个方法,然后在某个事件发生时,由接收方法调用这个方法

using System;namespace 练习
{// 定义一个名为Button的类,用于模拟一个按钮的行为class Button{// 定义一个委托类型MyButtonpublic delegate void MyButton();// ClickButton是一个委托类型的成员变量,用于存储按钮点击时的回调方法public MyButton ClickButton;public void Click(){Console.WriteLine("准备点击按钮");if (ClickButton != null){ClickButton();}}}internal class Program{static void MyClick(){Console.WriteLine("按钮被点击了!");}static void Main(string[] args){// 创建Button类的一个实例Button button = new Button();            // 将ClickButton委托设置为引用MyClick方法,这样点击按钮时会调用MyClickbutton.ClickButton = new Button.MyButton(MyClick);           // 模拟点击按钮,这将触发ClickButton委托,调用MyClick方法button.Click();         Console.Read();}}
}
  • 事件处理

事件是基于委托实现的。事件允许对象在发生特定行为时通知其他对象,而委托提供了一种机制来注册和触发这些通知

  • 多播委托

即一个委托可以引用多个方法。这使得你可以将多个方法链接在一起,以便它们可以依次或同时被调用。委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。

using System;namespace 委托的多播
{internal class Program{// 定义一个委托类型CalculateDelegate,它可以引用接受两个int参数并返回int的方法public delegate int CalculateDelegate(int x, int y);// Add方法实现了CalculateDelegate委托的签名,用于加法运算public static int Add(int x, int y){// 输出加法运算的结果Console.WriteLine(x + y);return x + y;}// Multiply方法实现了CalculateDelegate委托的签名,用于乘法运算public static int Multiply(int x, int y){// 输出乘法运算的结果Console.WriteLine(x * y);return x * y;}static void Main(string[] args){// 创建CalculateDelegate委托的实例cal0,引用Add方法CalculateDelegate cal0 = new CalculateDelegate(Add);// 创建CalculateDelegate委托的实例cal1,引用Multiply方法CalculateDelegate cal1 = new CalculateDelegate(Multiply);// 通过委托的加法运算创建一个多播委托cal,它将依次执行cal0和cal1引用的方法CalculateDelegate cal = cal0 + cal1;// 调用多播委托cal,传入1和3作为参数// 这将依次调用Add和Multiply方法,并输出结果cal(1, 3);Console.ReadKey();}}
}
  • 泛型委托

以引用具有泛型参数的方法,从而提供类型安全和灵活性

using System;// 定义一个泛型委托
public delegate R MyFunc<T, R>(T t);class Program
{// 一个接受整数并返回字符串的方法static string ConvertToString(int number){return number.ToString();}static void Main(){// 创建泛型委托的实例,引用一个方法MyFunc<int, string> toString = ConvertToString;// 使用委托调用方法string result = toString(123);Console.WriteLine(result); // 输出 "123"// 可以引用不同类型的方法MyFunc<double, int> round = Math.Round;int roundedResult = round(3.14159); // 调用 Math.Round 方法Console.WriteLine(roundedResult); // 输出 "3"}
}
  • 法的抽象表示

委托允许你将方法视为一个对象,这使得方法可以像其他对象一样被传递、存储和操作

using System;namespace MethodAbstractionExample
{// 定义一个委托类型,它抽象表示一个方法,该方法接受两个int参数并返回一个int结果public delegate int Operation(int x, int y);class Program{// 这是一个具体的加法方法,符合委托的签名public static int Add(int a, int b){return a + b;}// 这是一个具体的减法方法,也符合委托的签名public static int Subtract(int a, int b){return a - b;}static void Main(string[] args){// 创建委托实例,将加法方法作为抽象方法引用Operation operation = new Operation(Add);int result = operation(5, 3); // 调用抽象方法,实际执行加法Console.WriteLine($"结果是: {result}"); // 输出 8// 可以改变委托引用的方法,以抽象表示不同的方法operation = new Operation(Subtract);result = operation(5, 3); // 这次实际执行的是减法Console.WriteLine($"结果是: {result}"); // 输出 2// 等待用户输入,以便查看控制台输出Console.ReadLine();}}
}
  • 匿名方法和 Lambda 表达式

public delegate void MyDelegate(string message);public class Program
{public static void Main(){MyDelegate del = delegate (string msg){Console.WriteLine(msg);};del("!");}
}
public delegate void MyDelegate(string message);public class Program
{public static void Main(){MyDelegate del = (msg) => Console.WriteLine(msg);del("!");}
}

为什么使用委托

委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。与 C 或 C++ 中的函数指针不同,委托是类型安全的,并且是面向对象的。委托不仅能够实现代码的重用,还能促进逻辑的解耦,从而提高代码的可维护性和可扩展性。


其他委托形式

Action

  • Action 表示无参数且无返回值的委托。
  • Action<int, string> 是一个带有参数且无返回值的泛型委托,最多支持16个参数。
  • Action 可以涵盖所有无返回值的委托,是对无返回值委托的一个统一封装。
using System;public class Program
{static void DisplayMessage(){Console.WriteLine("Hello, World!");}static void DisplayMessage(string message){Console.WriteLine(message);}public static void Main(){// 无参数 ActionAction actionWithoutParams = DisplayMessage;actionWithoutParams(); // 输出 "Hello, World!"// 带参数 ActionAction<string> actionWithParams = DisplayMessage;actionWithParams("Hello!"); // 输出 "Hello!"}
}

Func

  • Func 是一种表示有返回值的委托,它必须返回一个值。
  • Func 可以无参数,也可以接受最多16个参数,其中最后一个参数指定返回值的类型。
  • Func 的使用方式与 delegate 相同,但它专门用于处理有返回值的情况,为这些委托提供了一个统一的封装。
using System;public class Program
{// Func 示例,接受两个int参数,返回它们的和static int Sum(int x, int y){return x + y;}public static void Main(){// 创建 Func 委托实例Func<int, int, int> sumFunc = Sum;// 调用 Func 委托int result = sumFunc(5, 10); // 返回 15Console.WriteLine($"result: {result}");}
}

 Predicate<T>

用于表示接受一个类型为 T 的参数并返回 bool 的方法。我们展示了如何使用筛选数组中的偶数

using System;
using System.Linq;public class Program
{public static void Main(){// 创建一个整数数组int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };// 使用 Predicate<T> 来筛选数组中的偶数Predicate<int> isEven = number => number % 2 == 0;// 筛选出所有偶数int[] evenNumbers = numbers.Where(isEven).ToArray();// 输出筛选结果Console.WriteLine("numbers:");foreach (var number in evenNumbers){Console.WriteLine(number);}}
}

这篇关于C# 委托详解(Delegate)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115839

相关文章

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数

Python装饰器之类装饰器详解

《Python装饰器之类装饰器详解》本文将详细介绍Python中类装饰器的概念、使用方法以及应用场景,并通过一个综合详细的例子展示如何使用类装饰器,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录1. 引言2. 装饰器的基本概念2.1. 函数装饰器复习2.2 类装饰器的定义和使用3. 类装饰

MySQL 中的 JSON 查询案例详解

《MySQL中的JSON查询案例详解》:本文主要介绍MySQL的JSON查询的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 的 jsON 路径格式基本结构路径组件详解特殊语法元素实际示例简单路径复杂路径简写操作符注意MySQL 的 J

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中的@SneakyThrows注解用法详解

《Java中的@SneakyThrows注解用法详解》:本文主要介绍Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常... 目录前言一、@SneakyThrows 简介1.1 什么是 Lombok?二、@SneakyThrows

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Redis Pipeline(管道) 详解

《RedisPipeline(管道)详解》Pipeline管道是Redis提供的一种批量执行命令的机制,通过将多个命令一次性发送到服务器并统一接收响应,减少网络往返次数(RTT),显著提升执行效率... 目录Redis Pipeline 详解1. Pipeline 的核心概念2. 工作原理与性能提升3. 核

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中