目录
[delegate delegate delegate](#delegate delegate delegate)
[多播委托(Multicast Delegate)](#多播委托(Multicast Delegate))
[1、Action 委托](#1、Action 委托)
[表示无返回值的方法,支持 0~16 个参数。](#表示无返回值的方法,支持 0~16 个参数。)
[示例 1:无参数](#示例 1:无参数)
[示例 2:带参数](#示例 2:带参数)
[2、Func 委托](#2、Func 委托)
[示例 1:无参数有返回值](#示例 1:无参数有返回值)
[示例 2:带参数有返回值](#示例 2:带参数有返回值)
[示例 1:筛选整数集合](#示例 1:筛选整数集合)
[示例 2:筛选字符串集合](#示例 2:筛选字符串集合)
一、什么是委托?
定义:委托(Delegate) 是 C# 中一种类型安全的函数指针机制,本质是一个类(继承自 System.MulticastDelegate
),用于封装一个或多个具有相同签名(参数和返回值类型)的方法。委托的核心作用是将方法作为参数传递,或动态调用多个方法,实现回调机制和事件驱动编程。
关键点:
委托是类型安全的,编译器会检查方法签名是否匹配。
委托可以指向静态方法或实例方法。
委托是面向对象的,比 C/C++ 的函数指针更安全。
叽里咕噜说啥呢,看不懂。说人话就是,一个函数变量, 你可以把他理解为一个函数的容器,就像你申明一个int类型的数据,这个数据装载着一个整型数据,委托也是一样,只不过装的是函数。
委托是 函数的容器
可以理解为表示函数的变量类型
用来存储传递函数的方法
委托的本质是一个类 用来定义函数的类型(返回值和参数的类型)
不同的 函数 必须对应各自"格式"一致的委托
二、委托的作用
-
解耦调用方与被调用方
调用方无需直接依赖具体方法,只需通过委托调用,提升代码灵活性。
-
实现回调机制
例如异步编程中,方法完成后通过委托通知调用方。
-
事件处理的基础
事件(Event)本质是委托的封装,用于实现观察者模式。这点我们后面会学到的,今天先了解。
-
多播(Multicast)能力
一个委托可以绑定多个方法,按顺序执行。
-
支持 Lambda 表达式和匿名方法
简化代码,尤其在 LINQ 和异步编程中广泛应用。这是一个很方便的方式写函数,我们后面学习。
三、委托的基本声明规则
请务必记住一个关键字
delegate delegate delegate
委托的声明语法 其实就是在函数前面加了一个关键字同时去除了函数体
关键字:delegate
语法:访问修饰符 delegate 返回值类型 委托名称(参数列表);
写在哪里
可以申明在namespace中也可以写在class中
更多的写在namespace中简单的记忆委托语法 就是:函数申明语法前面加一个delegate关键字
委托的定义
访问修饰符不写 默认是public 在别的命名空间中也可以访问
private 别的空间就不能用了
一般用public
cs
delegate [返回类型] DelegateName([参数列表]);
例如:
cs
delegate int Calculate(int a, int b);
方法签名必须匹配
委托指向的方法必须与委托的参数类型、顺序、数量 和返回类型完全一致。
实例化委托
必须通过 new
关键字或直接赋值方法名初始化:
cs
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;
一些申明示例:
下面提到的必须静态 指的是 因为你要在主函数中使用,所以必须静态
无参数无返回值的委托
cs
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!"
}
}
有参数无返回值的委托
cs
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
}
}
无参数有返回值的委托
cs
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(示例值)
}
}
有参数有返回值的委托
cs
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
}
}
单个泛型的委托
cs
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()); // 输出:42
Console.WriteLine(getString()); // 输出:Hello
}
}
多个泛型:
cs
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)
委托支持通过 +=
和 -=
运算符绑定多个方法,调用时会按添加顺序依次执行所有绑定的方法。这一特性使得委托可以轻松实现"一对多"的方法调用,常用于需要批量触发操作的场景。
cs
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("系统启动成功");
// 输出:
// [控制台] 系统启动成功
// [弹窗] 系统启动成功
}
}
动态切换方法逻辑
委托允许运行时动态绑定不同方法,实现灵活的策略模式。例如,根据配置切换不同的算法实现:
cs
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
}
}
将方法作为参数传递
委托可以将方法作为参数传递给其他方法,实现高度灵活的代码设计。例如,定义一个通用的数据处理方法:
cs
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:无参数
cs
using System;
public class Program
{
static void PrintHello()
{
Console.WriteLine("Hello, Action!");
}
static void Main()
{
Action action = PrintHello;
action(); // 输出: Hello, Action!
}
}
示例 2:带参数
cs
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:无参数有返回值
cs
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:带参数有返回值
cs
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:筛选整数集合
cs
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:筛选字符串集合
cs
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
)及函数式编程范式的关键基础。