目录
[一、自定义委托 delegate](#一、自定义委托 delegate)
[1. 委托定义规则](#1. 委托定义规则)
[2. 委托核心作用:方法参数(回调)](#2. 委托核心作用:方法参数(回调))
[1. 三种赋值写法](#1. 三种赋值写法)
[2. 两种调用方式 + 空安全校验](#2. 两种调用方式 + 空安全校验)
[三、多播委托(+=、-= 绑定多个方法)](#三、多播委托(+=、-= 绑定多个方法))
[1. 核心特点](#1. 核心特点)
[2. 移除绑定注意事项](#2. 移除绑定注意事项)
[四、系统内置三大委托(不用自己手写 delegate)](#四、系统内置三大委托(不用自己手写 delegate))
[五、实战:仿照 Array.Find 手写自定义查找方法](#五、实战:仿照 Array.Find 手写自定义查找方法)
[1. 自定义泛型委托](#1. 自定义泛型委托)
[2. 封装通用 Find](#2. 封装通用 Find)
一、自定义委托 delegate
1. 委托定义规则
delegate 返回值 委托名(参数列表),委托签名必须和绑定的方法完全一致(返回值、参数个数 / 类型匹配),委托本质是一个特殊类。
cs
//无参无返回委托
public delegate void MyDel1();
//两个int入参、int返回值委托
public delegate int MyDel2(int a, int b);
2. 委托核心作用:方法参数(回调)
把委托作为形参,调用方法时传入目标函数,方法内部通过委托变量间接执行传入的逻辑,也就是回调。
cs
class Test
{
//委托充当参数,接收同格式方法
public static void F1(MyDel1 func)
{
func();//执行外部传入的方法
}
}
//调用
static void test() => Console.WriteLine("test");
Test.F1(test);
二、委托实例化与调用
1. 三种赋值写法
cs
//1.new关键字实例绑定方法
MyDel1 m1 = new MyDel1(F1);
//2.简写:直接赋值方法名(语法糖)
MyDel1 m2 = F2;
//3.实例方法绑定:需要先创建对象
MyDel2 m3 = new MyDel2(new Test().Add);
MyDel2 m4 = new Test().Add;
2. 两种调用方式 + 空安全校验
- 直接括号调用:
m1(10,"aaa"); - Invoke 显式调用:
m1.Invoke(10,"aaa"); - 空值简化判断:
m1?.Invoke(10,"aaa");(变量非空才执行,防止空引用报错)
cs
MyDel2 m5 = null;
m5?.Invoke(10,20);
三、多播委托(+=、-= 绑定多个方法)
1. 核心特点
- 使用
+=追加绑定多个方法,-=移除绑定的方法; - 执行委托时,按绑定顺序依次执行所有绑定的方法;
- 多播委托不适合带返回值场景(仅能拿到最后一个方法返回值),大多配合无返回
void方法使用。
2. 移除绑定注意事项
- 实例方法移除:绑定和移除必须使用同一个对象实例,new 两次对象是不同实例,无法移除;
- 静态方法移除:直接
-=方法名即可,不受对象影响。
cs
public delegate void MyDel(string s);
//正确移除实例方法
MyDel m4 = F1;
Test t1 = new Test();
m4 += t1.F2;
m4 -= t1.F2;
//静态方法
m4 += Test.F3;
m4 -= Test.F3;
四、系统内置三大委托(不用自己手写 delegate)
.NET 预先封装好三种通用委托,日常开发优先使用,不用重复自定义委托:
| 委托 | 作用 | 格式说明 |
|---|---|---|
| Action | 无返回值 | Action无参;Action<T1,T2>带多个参数、无返回 |
| Func | 带返回值 | 最后一个泛型是返回值类型,前面全是参数:Func<int,string>入参 int、返回 string |
| Predicate | 固定返回 bool | Predicate<T>单个 T 参数,返回布尔,多用于条件筛选 |
cs
//Action:无返回
static void F1(Action<int> action) => action?.Invoke(10);
//Func:带返回
static void F2(Func<int,string> func) => func?.Invoke(10);
//Predicate:返回bool
static void F3(Predicate<int> pre) => pre(10);
//调用搭配Lambda
F1(v=>Console.WriteLine(v));
F2(v=>v.ToString());
F3(v=>v>5);
五、实战:仿照 Array.Find 手写自定义查找方法
用委托实现自定义数组查找,对比原生Array.Find,理解回调筛选原理:
cs
public class MyArray
{
//使用内置Func
public static int MyFind1(int[] arr, Func<int, bool> f1)
{
for (int i = 0; i < arr.Length; i++)
{
if (f1(arr[i])) return arr[i];
}
return -1;
}
//自定义委托实现同等效果
public delegate bool CallBack(int a);
public static int MyFind2(int[] arr, CallBack f1)
{
for (int i = 0; i < arr.Length; i++)
{
if (f1(arr[i])) return arr[i];
}
return -1;
}
}
//使用
int[] arr = {1,2,3,4,5,6};
Console.WriteLine(MyArray.MyFind1(arr,v=>v%2==0));
六、泛型委托(适配任意数据类型)
1. 自定义泛型委托
delegate bool CallBack<T>(T v);,泛型 T 随调用时数组类型自动改变,一套代码支持 int、string、自定义类等任意数组筛选。
2. 封装通用 Find
cs
public delegate bool CallBack<T>(T v);
public static T Find<T>(T[] arr, CallBack<T> c)
{
for (int i = 0; i < arr.Length; i++)
{
if (c(arr[i])) return arr[i];
}
return default(T);
}
//调用
int[] intArr = {1,2,3};
string[] strArr = {"aa","bb","cc"};
Find(intArr, v=>v%2==0);
Find(strArr, v=>v.StartsWith("a"));
//系统自带Predicate<T>就是官方泛型布尔委托
public static T Find1<T>(T[] arr, Predicate<T> c)
七、核心知识点总结
- 委托本质:引用类型,用来保存方法地址,实现方法当做参数传递(回调);
- 实例方式 :
new委托(方法)/ 直接赋值方法名,Invoke()或括号调用,?.Invoke()空安全; - 多播委托 :
+=绑定多个方法、-=解绑,实例方法解绑需同一个对象; - 内置委托:Action 无返回、Func 有返回、Predicate 返回 bool,替代自定义 delegate;
- 泛型委托 :
委托名<T>实现通用逻辑,兼容任意类型,是 LINQ、数组高阶方法底层。