-
委托(Delegate):方法的“指针”
委托(Delegate):方法的“指针”
-
委托的核心定义与价值
委托是C#中的引用类型,用于封装方法的签名(参数+返回值)和目标方法,相当于方法的“安全指针”或“回调接口”。其核心价值在于:
解耦代码:将方法调用与具体实现分离(如事件驱动中的观察者模式);
动态调用:运行时可切换委托指向的方法;
支持多播:一个委托实例可指向多个方法,批量执行。
语法规则:
用delegate关键字声明委托类型;
委托的签名必须与目标方vb.net教程C#教程python教程SQL教程access 2010教程法完全匹配;
委托实例可直接调用,或通过Invoke()/BeginInvoke()异步调用。 -
委托的基础用法
本节通过“计算两个数”的例子,展示委托的声明、实例化、调用流程。
2.1 完整代码实现
csharp
using System;
// 1. 声明委托类型:接受两个int参数,返回int
delegate int CalculateDelegate(int a, int b);
class Program
{
// 目标方法1:加法
static int Add(int x, int y) => x + y;
// 目标方法2:减法
static int Subtract(int x, int y) => x - y;
static void Main()
{
// 2. 实例化委托:指向Add方法
CalculateDelegate calc = Add;
// 3. 调用委托:相当于调用Add(5,3)
int addResult = calc(5,3);
Console.WriteLine($"加法结果:{addResult}"); // 输出8
// 切换委托指向Subtract方法
calc = Subtract;
int subResult = calc(5,3);
Console.WriteLine($"减法结果:{subResult}"); // 输出2
// 显式调用Invoke方法(与直接调用等价)
int subResult2 = calc.Invoke(10,4);
Console.WriteLine($"显式调用结果:{subResult2}"); // 输出6
}
}
2.2 逐行代码讲解
委托声明:delegate int CalculateDelegate(int a, int b)
定义一个名为CalculateDelegate的委托类型,要求目标方法必须接受两个int参数并返回int。
目标方法:Add/Subtract
方法签名与委托完全匹配,可被委托封装。
实例化委托:CalculateDelegate calc = Add
将Add方法的引用赋值给委托实例calc,此时calc指向Add。
调用委托:calc(5,3)
直接调用委托,等价于执行Add(5,3);Invoke()是显式调用方式,结果一致。
切换方法:calc = Subtract
委托实例可动态切换指向的方法,体现灵活性。
3. 系统内置委托:简化开发
.NET框架提供了预定义委托类型,无需手动声明,直接使用即可。常用类型如下:
3.1 Action
Action系列委托用于封装无返回值的方法,支持0~16个参数。
示例:
csharp
// Action<int>:接受1个int参数,无返回值
Action<int> printNumber = num => Console.WriteLine($"数字:{num}");
printNumber(100); // 输出:数字:100
// Action<string, int>:接受string和int参数,无返回值
Action<string, int> printUser = (name, age) => Console.WriteLine($"姓名:{name},年龄:{age}");
printUser("张三",25); // 输出:姓名:张三,年龄:25
3.2 Func
Func系列委托用于封装有返回值的方法,支持1~17个参数(最后一个为返回类型)。
示例:
csharp
// Func<int, int, int>:接受2个int参数,返回int
Func<int, int, int> multiply = (a,b) => a*b;
int product = multiply(4,5); // 结果:20
// Func<string, bool>:接受string参数,返回bool
Func<string, bool> isEmpty = s => string.IsNullOrEmpty(s);
bool result = isEmpty(""); // 结果:true
3.3 Predicate
Predicate
示例:
csharp
// Predicate<string>:判断字符串长度是否大于5
Predicate<string> isLongString = s => s.Length >5;
bool isLong = isLongString("HelloWorld"); // 结果:true
-
多播委托:批量执行方法
委托支持多播(Multicast),即一个委托实例可指向多个方法,调用时按添加顺序执行所有方法。
4.1 完整代码实现
csharp
using System;
// 无返回值的委托类型
delegate void ShowMessageDelegate();
class Program
{
static void ShowWelcome() => Console.WriteLine("欢迎光临!");
static void ShowGoodbye() => Console.WriteLine("再见!");
static void ShowNotice() => Console.WriteLine("今日活动:全场8折!");
static void Main()
{
// 1. 实例化多播委托
ShowMessageDelegate show = ShowWelcome;
// 2. 添加方法(+=)
show += ShowGoodbye;
show += ShowNotice;
// 3. 调用委托:执行所有方法
Console.WriteLine("=== 第一次调用 ===");
show();
// 4. 移除方法(-=)
show -= ShowGoodbye;
Console.WriteLine("
=== 第二次调用 ===");
show();
}
}
4.2 输出结果与讲解
输出:
=== 第一次调用 ===
欢迎光临!
再见!
今日活动:全场8折!
=== 第二次调用 ===
欢迎光临!
今日活动:全场8折!
关键说明:
添加方法:用+=向委托实例添加方法;
移除方法:用-=从委托实例移除方法;
执行顺序:按添加顺序执行所有方法;
返回值问题:若委托有返回值,多播委托仅返回最后一个方法的结果,因此多播委托通常用于无返回值的场景(如Action)。
5. 基础知识拓展
5.1 委托的本质
每个委托类型都是System.Delegate的子类,可通过GetInvocationList()获取所有方法的列表:
csharp
// 遍历多播委托的所有方法
foreach (var method in show.GetInvocationList())
{
method.DynamicInvoke(); // 动态调用每个方法
}
5.2 委托与事件的关系
事件是委托的封装,用于限制外部对委托的操作(仅允许订阅+=/取消订阅-=,不能直接调用或赋值)。示例:
csharp
public class OrderService
{
// 声明事件(基于Action委托)
public event Action OnOrderCompleted;
public void CompleteOrder()
{
// 内部触发事件
OnOrderCompleted?.Invoke();
}
}
// 使用事件
var service = new OrderService();
service.OnOrderCompleted += () => Console.WriteLine("订单完成通知:邮件已发送");
service.CompleteOrder(); // 触发事件
5.3 委托与Lambda表达式
Lambda表达式可简化委托实例化,无需单独定义方法:
csharp
// 用Lambda代替单独的Add方法
CalculateDelegate calc = (a,b) => a + b;
int result = calc(3,4); // 7
5.4 异步委托调用
委托支持异步调用(BeginInvoke/EndInvoke),但现代C#更推荐用Task。示例:
csharp
// 异步调用委托
IAsyncResult ar = calc.BeginInvoke(5,3, null, null);
// 执行其他任务
// 获取异步结果
int result = calc.EndInvoke(ar);
-
总结
委托是C#中解耦与动态调用的核心工具:
核心作用:封装方法,实现代码分离与动态切换;
常用类型:Action(无返回)、Func(有返回)、Predicate(判断);
多播委托:批量执行多个方法;
拓展应用:事件、Lambda表达式、异步调用。
掌握委托是理解C#事件驱动编程、LINQ、异步编程的基础。
练习
实现一个“用户注册通知”系统:
1.声明委托UserRegisteredDelegate(接受string参数,无返回值);
2.定义两个方法:SendEmail(打印“发送邮件给xxx”)、SendSms(打印“发送短信给xxx”);
3.实例化多播委托,添加两个方法,调用委托模拟用户注册后的通知。
参考代码:
csharp
delegate void UserRegisteredDelegate(string username);
static void SendEmail(string name) => Console.WriteLine($"发送邮件给{name}");
static void SendSms(string name) => Console.WriteLine($"发送短信给{name}");
// 测试
UserRegisteredDelegate notify = SendEmail;
notify += SendSms;
notify("李四");
输出:
发送邮件给李四
发送短信给李四
(本节完)
下一章:事件(Event):委托的封装与应用
(深入讲解事件的本质、观察者模式、事件驱动编程)
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49374.html










