C#进阶学习(九)委托的介绍
目录
一、什么是委托?
二、委托的作用
三、委托的基本声明规则
delegate delegate delegate
四、委托的特点及用法
多播委托(Multicast Delegate)
动态切换方法逻辑
将方法作为参数传递
五、系统给我们提供好的委托
1、Action 委托
表示无返回值的方法,支持 0~16 个参数。
示例 1:无参数
示例 2:带参数
2、Func 委托
表示有返回值的方法,最后一个泛型参数为返回类型
示例 1:无参数有返回值
示例 2:带参数有返回值
3、Predicate 委托
专用于返回布尔值的方法,常见于集合操作。
示例 1:筛选整数集合
示例 2:筛选字符串集合
六、总结
一、什么是委托?
定义:委托(Delegate) 是 C# 中一种类型安全的函数指针机制,本质是一个类(继承自 System.MulticastDelegate
),用于封装一个或多个具有相同签名(参数和返回值类型)的方法。委托的核心作用是将方法作为参数传递,或动态调用多个方法,实现回调机制和事件驱动编程。
关键点:
委托是类型安全的,编译器会检查方法签名是否匹配。
委托可以指向静态方法或实例方法。
委托是面向对象的,比 C/C++ 的函数指针更安全。
叽里咕噜说啥呢,看不懂。说人话就是,一个函数变量, 你可以把他理解为一个函数的容器,就像你申明一个int类型的数据,这个数据装载着一个整型数据,委托也是一样,只不过装的是函数。
委托是 函数的容器
可以理解为表示函数的变量类型
用来存储传递函数的方法
委托的本质是一个类 用来定义函数的类型(返回值和参数的类型)
不同的 函数 必须对应各自“格式”一致的委托
二、委托的作用
-
解耦调用方与被调用方
调用方无需直接依赖具体方法,只需通过委托调用,提升代码灵活性。 -
实现回调机制
例如异步编程中,方法完成后通过委托通知调用方。 -
事件处理的基础
事件(Event)本质是委托的封装,用于实现观察者模式。这点我们后面会学到的,今天先了解。 -
多播(Multicast)能力
一个委托可以绑定多个方法,按顺序执行。 -
支持 Lambda 表达式和匿名方法
简化代码,尤其在 LINQ 和异步编程中广泛应用。这是一个很方便的方式写函数,我们后面学习。
三、委托的基本声明规则
请务必记住一个关键字
delegate delegate delegate
委托的声明语法 其实就是在函数前面加了一个关键字同时去除了函数体
关键字:delegate
语法:访问修饰符 delegate 返回值类型 委托名称(参数列表);
写在哪里
可以申明在namespace中也可以写在class中
更多的写在namespace中简单的记忆委托语法 就是:函数申明语法前面加一个delegate关键字
委托的定义
访问修饰符不写 默认是public 在别的命名空间中也可以访问
private 别的空间就不能用了
一般用public
delegate [返回类型] DelegateName([参数列表]);
例如:
delegate int Calculate(int a, int b);
方法签名必须匹配
委托指向的方法必须与委托的参数类型、顺序、数量和返回类型完全一致。
实例化委托
必须通过 new
关键字或直接赋值方法名初始化:
Calculate calc1 = new Calculate(Add); // 传统方式
Calculate calc2 = Subtract; // C# 2.0 简化语法static int Add(int x, int y) => x + y;
static int Subtract(int x, int y) => x - y;
一些申明示例:
下面提到的必须静态 指的是 因为你要在主函数中使用,所以必须静态
无参数无返回值的委托
using System;// 1. 声明委托类型
delegate void SimpleDelegate();public class Program {// 2. 定义符合委托签名的方法(必须静态)static void SayHello() {Console.WriteLine("Hello!");}static void Main() {// 3. 创建委托实例并绑定方法SimpleDelegate greet = SayHello;// 4. 调用委托greet(); // 输出 "Hello!"}
}
有参数无返回值的委托
using System;// 声明委托
delegate void ParameterDelegate(int a, string b);public class Program {// 定义方法(必须静态)static void ShowInfo(int id, string name) {Console.WriteLine($"ID: {id}, Name: {name}");}static void Main() {// 创建委托实例并调用ParameterDelegate print = ShowInfo;print(101, "Alice"); // 输出:ID: 101, Name: Alice}
}
无参数有返回值的委托
using System;// 声明委托
delegate int ReturnValueDelegate();public class Program {// 定义方法(必须静态)static int GenerateRandom() {return new Random().Next(1, 100);}static void Main() {ReturnValueDelegate getNumber = GenerateRandom;int num = getNumber();Console.WriteLine($"随机数: {num}"); // 输出:随机数: 42(示例值)}
}
有参数有返回值的委托
using System;// 声明委托
delegate bool LogicDelegate(int x, int y);public class Program {// 定义方法(必须静态)static bool IsEqual(int a, int b) {return a == b;}static void Main() {LogicDelegate check = IsEqual;bool result = check(5, 5);Console.WriteLine($"是否相等: {result}"); // 输出:是否相等: True}
}
单个泛型的委托
using System;// 声明泛型委托
delegate T GenericDelegate<T>();public class Program {// 定义方法(必须静态)static int ReturnInt() => 42;static string ReturnString() => "Hello";static void Main() {GenericDelegate<int> getInt = ReturnInt;GenericDelegate<string> getString = ReturnString;Console.WriteLine(getInt()); // 输出:42Console.WriteLine(getString()); // 输出:Hello}
}
多个泛型:
using System;// 声明泛型委托
delegate TResult MultiGenericDelegate<T1, T2, TResult>(T1 a, T2 b);public class Program {// 定义方法(必须静态)static string MergeData(int count, string item) {return $"{count}个{item}";}static void Main() {MultiGenericDelegate<int, string, string> combine = MergeData;string output = combine(3, "苹果");Console.WriteLine(output); // 输出:3个苹果}
}
四、委托的特点及用法
多播委托(Multicast Delegate)
委托支持通过 +=
和 -=
运算符绑定多个方法,调用时会按添加顺序依次执行所有绑定的方法。这一特性使得委托可以轻松实现“一对多”的方法调用,常用于需要批量触发操作的场景。
using System;// 声明委托
delegate void MessageDelegate(string message);public class Program
{static void LogToConsole(string msg) {Console.WriteLine("[控制台] " + msg);}static void ShowPopup(string msg) {Console.WriteLine("[弹窗] " + msg); // 模拟弹窗逻辑}static void Main() {// 绑定两个方法MessageDelegate notify = LogToConsole;notify += ShowPopup;// 调用时依次执行notify("系统启动成功"); // 输出:// [控制台] 系统启动成功// [弹窗] 系统启动成功}
}
动态切换方法逻辑
委托允许运行时动态绑定不同方法,实现灵活的策略模式。例如,根据配置切换不同的算法实现:
using System;// 声明委托
delegate int MathOperation(int a, int b);public class Program
{static int Add(int x, int y) => x + y;static int Multiply(int x, int y) => x * y;static void Main() {MathOperation calculator;// 根据用户输入切换算法Console.Write("选择操作 (1=加法, 2=乘法): ");int choice = int.Parse(Console.ReadLine());calculator = (choice == 1) ? (MathOperation)Add : Multiply;int result = calculator(3, 4);Console.WriteLine("结果: " + result); // 输出 7 或 12}
}
将方法作为参数传递
委托可以将方法作为参数传递给其他方法,实现高度灵活的代码设计。例如,定义一个通用的数据处理方法:
using System;// 声明委托
delegate string FormatterDelegate(string input);public class Program
{// 通用格式化方法static string ProcessText(string text, FormatterDelegate formatter) {return formatter(text);}// 具体格式化逻辑static string ToUpper(string s) => s.ToUpper();static string Reverse(string s) {char[] arr = s.ToCharArray();Array.Reverse(arr);return new string(arr);}static void Main() {string input = "hello";string upperText = ProcessText(input, ToUpper);Console.WriteLine(upperText); // 输出 "HELLO"string reversedText = ProcessText(input, Reverse);Console.WriteLine(reversedText); // 输出 "olleh"}
}
五、系统给我们提供好的委托
1、Action
委托
-
表示无返回值的方法,支持 0~16 个参数。
使用示例:
示例 1:无参数
using System;public class Program
{static void PrintHello() {Console.WriteLine("Hello, Action!");}static void Main() {Action action = PrintHello;action(); // 输出: Hello, Action!}
}
示例 2:带参数
using System;public class Program
{static void ShowMessage(string message, int repeat) {for (int i = 0; i < repeat; i++) {Console.WriteLine(message);}}static void Main() {Action<string, int> actionWithParams = ShowMessage;actionWithParams("Action 示例", 3); // 输出 3 次 "Action 示例"}
}
可以看出 和我们自定义的委托是一样的,只不过系统帮助我们声明好了
2、Func
委托
-
表示有返回值的方法,最后一个泛型参数为返回类型
示例 1:无参数有返回值
using System;public class Program
{static int GetAnswer() {return 42;}static void Main() {Func<int> func = GetAnswer;int result = func();Console.WriteLine(result); // 输出: 42}
}
示例 2:带参数有返回值
using System;public class Program
{static string Combine(int a, string b) {return $"{a}{b}";}static void Main() {Func<int, string, string> funcWithParams = Combine;string output = funcWithParams(10, "Apples");Console.WriteLine(output); // 输出: 10Apples}
}
3、Predicate<T>
委托
-
专用于返回布尔值的方法,常见于集合操作。
示例 1:筛选整数集合
using System;
using System.Collections.Generic;public class Program
{static bool IsEven(int number) {return number % 2 == 0;}static void Main() {List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };Predicate<int> predicate = IsEven;// 筛选所有偶数List<int> evenNumbers = numbers.FindAll(predicate);foreach (var num in evenNumbers) {Console.WriteLine(num); // 输出: 2, 4}}
}
示例 2:筛选字符串集合
using System;
using System.Collections.Generic;public class Program
{static bool HasLetterA(string text) {return text.Contains("A", StringComparison.OrdinalIgnoreCase);}static void Main() {List<string> words = new List<string> { "Apple", "Banana", "Cherry" };Predicate<string> predicate = HasLetterA;// 筛选包含字母 A 的单词List<string> filteredWords = words.FindAll(predicate);foreach (var word in filteredWords) {Console.WriteLine(word); // 输出: Apple, Banana}}
}
委托类型 | 返回值 | 典型应用场景 | 示例方法签名 |
---|---|---|---|
Action | void | 执行无返回值的操作 | void Log(string message) |
Func | 任意 | 需要返回结果的计算或处理 | int Add(int a, int b) |
Predicate<T> | bool | 集合筛选、条件判断 | bool IsValid(string input) |
六、总结
C#中的委托(Delegate)是一种强大的机制,允许开发者以类型安全的方式将方法视为对象进行操作。其核心概念可总结如下:
1. 本质与定义
委托本质上是一个封装方法的类(继承自System.MulticastDelegate
),类似于函数指针,但更安全。它如同一个"函数容器",可存储与委托签名(参数类型、顺序、返回值)完全匹配的方法。例如,声明delegate int Calculate(int a, int b)
后,该委托可装载任何接收两个整数并返回整数的函数(如加法和减法)。
2. 核心作用
动态调用方法:运行时决定调用的具体方法,如根据用户输入切换算法(加法/乘法)。
实现回调机制:将方法作为参数传递,例如在数据处理时灵活注入不同的格式化逻辑(如转大写或反转字符串)。
事件驱动编程:多播委托通过
+=
绑定多个方法,实现事件触发时批量执行(如同时记录日志和弹出提示)。
3. 声明与使用规则
使用
delegate
关键字声明,方法需严格匹配签名。实例化时可直接赋值方法名(
Calculate calc = Add;
)或通过new
关键字。静态方法需在类中声明为
static
以供主函数调用。
4. 关键特性
多播能力:通过
+=
/-=
绑定多个方法,调用时按添加顺序执行,常用于需要多级处理的场景(如日志系统的多输出源)。泛型支持:如
delegate TResult MultiGenericDelegate<T1, T2, TResult>(T1 a, T2 b)
,提升代码复用性,适应不同类型组合。
5. 系统内置委托
Action:无返回值方法(支持0-16参数),如
Action<string>
表示接收字符串无返回的操作。Func:带返回值方法(最后泛型为返回类型),如
Func<int, int, bool>
判断两数是否相等。Predicate<T>:专用于返回布尔值的方法,常见于集合筛选(如
List.FindAll(predicate)
)。
实际应用价值
委托极大地提升了代码的灵活性与扩展性。例如,在GUI开发中,按钮点击事件通过委托绑定多个响应逻辑;在LINQ查询中,Where
方法通过Func<T, bool>
委托实现动态过滤条件。系统内置的Action
和Func
更简化了代码,避免了重复定义委托类型的繁琐。理解委托机制,是掌握C#事件、异步编程(如async/await
)及函数式编程范式的关键基础。