7.7 KiB
委托
概念: 委托是==可以引用方法的类型== 可以理解为“函数的容器”或“存方法的变量”
作用:
- 把方法赋值给变量
- 把方法作为参数传递
- 让一个地方可以调用多个方法
- 为事件、匿名函数、lambda 提供基础
简单理解: 普通变量存数据 委托变量存“符合条件的方法”
通常用法
- 作为类的成员,保存回调方法
- 作为方法参数,让调用者决定具体执行什么逻辑
- 同时绑定多个方法,实现多播调用
- 配合
Action、Func、匿名函数和 lambda 使用
实际开发中:
自定义委托仍然会用到
但很多简单场景更常使用系统自带的 Action 和 Func
语法
关键字:
delegate
定义委托:
访问修饰符 delegate 返回值类型 委托名(参数列表);
示例:
public delegate void MyDelegate(string message);
说明:
MyDelegate 只能保存:
参数是 string
返回值是 void
的方法
基础案例
using System;
public delegate void MyDelegate(string message);
class Program
{
static void PrintMessage(string message)
{
Console.WriteLine(message);
}
static void Main(string[] args)
{
MyDelegate del = PrintMessage;
del("你好,委托");
}
}
输出:
你好,委托
理解:
MyDelegate规定了方法的格式PrintMessage的参数和返回值符合这个格式- 所以可以赋值给
del - 调用
del(...),本质上就是调用PrintMessage(...)
方法必须匹配委托格式
public delegate int Calculate(int a, int b);
static int Add(int a, int b)
{
return a + b;
}
Calculate calculate = Add;
Console.WriteLine(calculate(10, 20));
正确匹配: 参数数量一致 参数类型一致 返回值类型一致
错误示例:
static void Print(int a, int b)
{
}
// Calculate calculate = Print;
原因:
Calculate 要求返回 int
Print 的返回值是 void
两者不匹配
委托的赋值和调用
赋值:
MyDelegate del = PrintMessage;
调用:
del("hello");
也可以使用 Invoke:
del.Invoke("hello");
通常写法:
直接写 del(...) 更常见
Invoke(...) 的语义更明确
委托可以作为参数
作用: 把“具体要做什么”交给调用者决定
using System;
public delegate void HandleNumber(int number);
class Program
{
static void Process(int number, HandleNumber handler)
{
handler(number);
}
static void PrintNumber(int number)
{
Console.WriteLine("数字:" + number);
}
static void PrintDouble(int number)
{
Console.WriteLine("两倍:" + number * 2);
}
static void Main(string[] args)
{
Process(10, PrintNumber);
Process(10, PrintDouble);
}
}
输出:
数字:10
两倍:20
理解:
Process 不关心具体处理方式
只要求传进来的方法符合 HandleNumber 的格式
多播委托
一个委托变量可以同时绑定多个方法:
using System;
public delegate void MyDelegate();
class Program
{
static void Method1()
{
Console.WriteLine("执行方法1");
}
static void Method2()
{
Console.WriteLine("执行方法2");
}
static void Main(string[] args)
{
MyDelegate del = Method1;
del += Method2;
del();
}
}
输出:
执行方法1
执行方法2
取消绑定:
del -= Method2;
说明:
+=用来添加方法-=用来移除方法- 调用时会按添加顺序依次执行
- 多播委托最适合返回值为
void的情况
有返回值的多播委托
public delegate int Calculate();
static int Method1()
{
return 1;
}
static int Method2()
{
return 2;
}
Calculate calculate = Method1;
calculate += Method2;
int result = calculate();
Console.WriteLine(result);
输出:
2
说明: 两个方法都会执行 但委托调用的最终返回值,只会保留最后一个方法的返回值
所以:
多播委托通常更适合 void 返回值
空委托要先判断
错误示例:
MyDelegate del = null;
// del();
原因:
委托变量是引用类型
没有绑定方法时可能为 null
常见写法:
if (del != null)
{
del();
}
更简洁的写法:
del?.Invoke();
说明:
?. 会先判断 del 是否为 null
不为 null 才调用 Invoke()
Action
Action 是系统自带的委托类型:
==无返回值==
无参:
Action action = PrintHello;
action();
static void PrintHello()
{
Console.WriteLine("Hello");
}
有参数:
Action<string> print = PrintMessage;
print("你好");
static void PrintMessage(string message)
{
Console.WriteLine(message);
}
说明:
Action 后面的泛型参数表示方法参数类型
它的返回值始终是 void
Func
Func 是系统自带的泛型委托类型:
==有返回值==
Func<int, int, int> add = Add;
int result = add(10, 20);
Console.WriteLine(result);
static int Add(int a, int b)
{
return a + b;
}
说明:
Func<参数1类型, 参数2类型, 返回值类型>
上面的:
Func<int, int, int>
表示:
前两个 int 是参数类型
最后一个 int 是返回值类型
自定义委托、Action、Func 的区别
| 对比点 | 自定义委托 | Action |
Func |
|---|---|---|---|
| 是否需要自己声明 | 需要 | 不需要 | 不需要 |
| 返回值 | 自己定义 | 必须是 void |
必须有返回值 |
| 参数 | 自己定义 | 可有多个 | 可有多个 |
| 常见用途 | 语义明确的回调 | 简单无返回值操作 | 简单有返回值操作 |
实际使用建议:
- 简单无返回值回调,优先考虑
Action - 简单有返回值回调,优先考虑
Func - 需要清晰业务语义时,可以定义自己的委托类型
和事件的关系
委托: 可以在类外部赋值 也可以在类外部直接调用
事件: 是对委托的进一步封装 类外部只能订阅和取消订阅 不能直接调用事件
可以和事件一起理解: 委托负责“存方法和调用方法” 事件负责“更安全地对外发布通知”
注意
- 委托是一种引用类型
- 委托变量只能保存签名匹配的方法
- 签名主要看参数和返回值
- 委托可以绑定一个或多个方法
+=添加方法,-=移除方法- 调用可能为
null的委托前要先判断 Action无返回值,Func有返回值- 自定义委托不能只靠返回值不同来重名
易错点
- 委托不是方法本身,而是“引用方法的变量”
- 委托类型和方法签名不匹配时,不能赋值
Add和+=不一样,委托绑定方法用+=- 多播委托有返回值时,只能拿到最后一个方法的返回值
del?.Invoke()可以避免空引用异常
一句话记忆
==委托就是一种可以存方法、传方法、调方法的类型。==
面试/复习时怎么说
可以这样答:
“委托是一种引用方法的类型,可以把符合指定签名的方法赋值给委托变量,再通过委托统一调用。
它可以作为参数传递,也可以绑定多个方法,常用于回调和事件机制。
实际开发中,简单场景通常使用系统自带的 Action 和 Func。”
引用:
- Microsoft Learn: Delegates
- Microsoft Learn: Action Delegate
- Microsoft Learn: Func Delegate
#委托 #delegate #Action #Func #进阶