【C#零基础进阶】委托(Delegate)超详细精讲,从原理到实战全覆盖
📌 前言
很多C#初学者在学习委托、事件、Lambda表达式时,总会感到困惑:委托到底是什么?为什么要用委托?委托和方法有什么区别?
委托是C#中面向对象、回调编程、事件机制、异步编程、框架设计的核心基础,几乎所有.NET高级特性都基于委托实现。吃透委托,才能真正理解C#的函数式编程思想、事件驱动模型。
本文将从零开始,通俗易懂讲解委托的全部核心知识点,搭配可直接运行的代码案例,帮助你们理解。
一、什么是委托?(核心定义)
1.1 官方定义
委托(Delegate)是一种用来存储、传递、调用方法的引用类型。
简单来说:委托就是方法的容器,是方法的“替身”。
1.2 通俗理解
普通变量存储的是数据(int、string、数组等);
委托变量存储的是方法(方法的地址、方法的逻辑)。
我们可以把方法赋值给委托、把委托当做参数传递、在任意位置通过委托执行对应的方法。
1.3 委托的本质
- 委托是引用类型,继承自 System.MulticastDelegate
- 委托是类型安全的:签名(返回值、参数列表)必须和匹配的方法完全一致
- 委托支持多播:一个委托可以绑定多个方法,一次性批量执行
二、委托的语法与基础使用
2.1 委托的声明语法
// 语法:修饰符 delegate 返回值类型 委托名(参数列表);
public delegate void MyDelegate(string msg);
声明规则:
2.2 委托的基础使用三步曲
2.3 完整入门案例
using System;
namespace DelegateDemo
{
// 1. 声明委托(无返回值、string参数)
public delegate void ShowMsgDelegate(string msg);
class Program
{
static void Main(string[] args)
{
// 3. 实例化委托,绑定方法
ShowMsgDelegate del = ShowMessage;
// 执行委托(调用绑定的方法)
del("Hello C#委托!");
del("CSDN技术分享");
}
// 2. 定义和委托签名匹配的方法
public static void ShowMessage(string message)
{
Console.WriteLine($"输出信息:{message}");
}
}
}
运行结果:
输出信息:Hello C#委托!
输出信息:CSDN技术分享
三、委托的核心特性
3.1 类型安全(最核心优势)
委托会严格校验返回值类型、参数个数、参数类型、参数顺序,不匹配直接编译报错,避免了C语言函数指针的不安全问题。
例:委托是 void (string),就不能绑定 int (int) 类型的方法。
3.2 委托可以作为方法参数(回调核心)
这是委托最常用、最重要的场景:将方法作为参数传递,实现回调逻辑、解耦代码。
实战案例:通用计算器
using System;
namespace DelegateDemo
{
// 声明计算委托
public delegate int CalcDelegate(int a, int b);
class Program
{
static void Main(string[] args)
{
// 传递不同方法,实现不同计算逻辑
Calc(10, 20, Add);
Calc(10, 20, Sub);
}
// 通用计算方法:委托作为参数
public static void Calc(int num1, int num2, CalcDelegate func)
{
int res = func(num1, num2);
Console.WriteLine($"计算结果:{res}");
}
// 加法方法
public static int Add(int a, int b) => a + b;
// 减法方法
public static int Sub(int a, int b) => a – b;
}
}
核心优势:无需修改Calc方法,只需要传入不同方法,就能扩展新功能,完美符合开闭原则。
3.3 多播委托(一个委托绑定多个方法)
委托支持 +=、-= 操作,可以绑定/解绑多个方法,执行时会按绑定顺序依次执行所有方法。
⚠️ 注意:有返回值的多播委托,只会获取最后一个方法的返回值,前面的返回值会被丢弃,日常开发中多播委托基本都用无返回值类型。
多播委托案例
using System;
namespace DelegateDemo
{
public delegate void MultiDelegate();
class Program
{
static void Main(string[] args)
{
MultiDelegate del = null;
// 绑定多个方法
del += Method1;
del += Method2;
del += Method3;
// 执行所有绑定的方法
del();
Console.WriteLine("=====解绑一个方法后=====");
// 解绑方法2
del -= Method2;
del();
}
public static void Method1() => Console.WriteLine("执行方法1");
public static void Method2() => Console.WriteLine("执行方法2");
public static void Method3() => Console.WriteLine("执行方法3");
}
}
四、.NET内置通用委托(不用手动声明)
日常开发中,90%场景不需要自己声明委托,.NET 内置了三套通用委托,覆盖所有常用场景:
4.1 Action 委托(无返回值)
- Action:无参数、无返回值
- Action<T1,T2…>:多个泛型参数、无返回值
4.2 Func 委托(有返回值) - Func<返回值类型>:无参数、有返回值
- Func<参数1,参数2…,返回值>:多参数、有返回值
4.3 Predicate 委托(固定返回bool) - Predicate:接收一个参数,固定返回 bool
- 多用于条件判断、集合筛选
4.4 内置委托实战演示
using System;
using System.Collections.Generic;
namespace DelegateDemo
{
class Program
{
static void Main(string[] args)
{
// Action 使用
Action show = msg => Console.WriteLine($“Action输出:{msg}”);
show(“测试Action委托”);
// Func 使用
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine($"Func计算结果:{add(20,30)}");
// Predicate 使用
Predicate<int> isOdd = num => num % 2 != 0;
Console.WriteLine($"5是否是奇数:{isOdd(5)}");
}
}
}
五、委托与Lambda表达式的关系
Lambda表达式就是委托的简写形式,用于快速生成匿名委托方法,简化代码。
所有Lambda表达式,最终都会编译为委托对象。
对比写法(传统委托 vs Lambda)
// 1. 传统匿名方法
Func<int,int> func1 = delegate(int num)
{
return num * num;
};
// 2. Lambda简写(更简洁)
Func<int,int> func2 = num => num * num;
日常开发中,优先使用 Lambda + 内置委托,极少手动声明自定义委托。
六、委托的经典使用场景
6.1 回调方法
异步操作完成后,通过委托回调通知结果,是异步编程的基础。
6.2 事件驱动(Winform/WPF/Unity)
事件本质是封装后的委托,所有按钮点击、窗口事件、Unity生命周期事件,全部基于委托实现。
6.3 集合高级操作(LINQ)
LINQ的 Where、Select、OrderBy 等方法,参数全部是 Func/Predicate 委托。
List list = new List{1,2,3,4,5};
// Where参数是Predicate委托
var res = list.Where(x => x > 3);
6.4 解耦代码、实现插件化
通过委托传递逻辑,让核心代码和业务代码分离,提升代码扩展性。
七、委托常见易错点与避坑指南
7.1 未初始化委托导致空指针异常
委托默认值为null,直接调用会报错,建议先判空:
if(del != null)
{
del();
}
// 简写方式
del?.Invoke();
7.2 多播委托返回值丢失
有返回值的多播委托,仅最后一个方法返回值生效,前面全部丢失,业务中尽量不用。
7.3 委托混淆重载方法
类中有多个重载方法时,委托绑定可能出现歧义,建议手动指定方法签名。
八、委托与事件的区别
九、全文总结
网硕互联帮助中心




评论前必须登录!
注册