一、委托核心定义(必背原话)
委托(delegate)是一种存储函数的引用类型。
委托的作用:用来匹配、存储、传递方法。
核心规则:定义委托时,必须和目标方法的返回值、参数列表、参数个数、参数类型完全一致。
通俗理解:委托就是方法的载体,可以把方法当做参数传递。
二、自定义委托语法(两种常用格式)
1. 无参数、无返回值委托
//定义一个不带参数、无返回值的委托类型 public delegate void MyDel1();匹配规则:只能接收void 无参的方法。
2. 带参数、带返回值委托
//定义带2个int参数、int返回值的委托类型 public delegate int MyDel2(int a, int b);匹配规则:只能接收返回值int、两个int参数的方法。
三、对应被传递的方法(委托适配方法)
//匹配 MyDel1(无参无返回) static void test() { Console.WriteLine("test"); } //匹配系统Func<int,int>(一个int参数、int返回值) static int test2(int a) { Console.WriteLine("test2"); return 10; } //匹配 MyDel2(两个int参数、int返回值) static int test3(int a,int b) { return 10; }四、核心用法:委托作为方法参数(回调机制)
最高频用法:将委托类型作为方法参数,实现【方法传递、方法回调】
1. 自定义委托 MyDel1 作为参数
public static void F1(MyDel1 func) { func(); //执行传递进来的方法 Console.WriteLine("F1"); }解析:
参数func是一个委托变量,可以接收匹配的方法
func():回调执行外部传进来的方法
2. 自定义委托 MyDel2 作为参数
public static void F3(MyDel2 f) { Console.WriteLine("F3"); }解析:接收双参、int返回值的方法,代码内可随时回调执行。
3. 系统内置委托 Func
//Func<参数类型,返回值类型> public static void F2(Func<int,int> func) { func(10); //回调执行传入的方法 Console.WriteLine("F2"); }知识点:
Func 是系统自带的有返回值委托
最后一个泛型参数 =返回值类型
前面泛型参数 =方法参数类型
Func<int,int>:代表【一个int参数、int返回值】的方法
五、Main 方法调用全程解析(执行顺序)
static void Main(string[] args) { Test.F1(test); Test.F2(test2); Test.F3(test3); }逐行执行流程
1. Test.F1(test)
把 test 方法传入 F1 → F1 内部执行 func() → 输出 test → 输出 F1
执行顺序:test方法 ==> F1
2. Test.F2(test2)
把 test2 方法传入 F2 → F2 内部执行 func(10) → 执行test2 → 输出 F2
执行顺序:test2方法 ==> F2
3. Test.F3(test3)
把 test3 方法传入 F3 → F3 直接输出 F3(未手动回调,test3不执行)
六、完整输出结果
test F1 test2 F2 F3七、自定义委托 VS 系统委托(必考)
1. 自定义 delegate
需要自己手动定义委托类型,灵活、适配任意场景
2. 系统内置委托
Func:有返回值的方法委托
Action:无返回值的方法委托
八、委托核心总结(简答题满分)
1. 委托是引用类型,专门用来存储、传递方法。
2. 委托定义必须和目标方法返回值、参数列表完全一致。
3. 委托最大作用:将方法作为参数传递,实现回调、解耦代码。
4. 自定义 delegate 灵活,系统 Func/Action 无需重复定义,开发更常用。
九、易错点总结
1. 参数不匹配、返回值不匹配 → 委托赋值报错
2. 委托参数方法,不调用 func() 就不会执行传入的方法
3. Func 最后一个泛型永远是返回值类型
委托实例化与调用(五种绑定+调用方式+数组高阶函数)
一、委托核心五要素(代码总结 必背)
1. 委托是引用类型;
2. 专门用来存储/绑定方法;
3. 可以通过实例化委托绑定匹配的方法;
4. 可以通过委托变量间接调用方法;
5. 可作为方法参数,实现回调函数机制。
二、自定义委托定义
//无返回值、int+string双参数委托 public delegate void MyDel1(int a, string b); //有返回值、两个int参数委托 public delegate int MyDel2(int a, int b);核心规则:委托签名必须和绑定方法的【返回值、参数个数、参数类型】完全一致。
三、被绑定的目标方法
1. 静态方法(Program类)
public static void F1(int a, string b) { Console.WriteLine($"F1方法a的值为:{a},b的值为:{b}"); } public static void F2(int a, string b) { Console.WriteLine($"F2方法a的值为:{a},b的值为:{b}"); }2. 实例方法(Test类)
class Test { public int Add(int a ,int b) { return a + b; } }四、委托四种绑定方式(重点必考)
方式1:完整实例化绑定(标准写法)
MyDel1 m1 = new MyDel1(F1); //调用 m1(10, "aaa");通过new 委托类型(方法名)显式实例化,最规范、底层标准写法。
方式2:语法糖简写绑定(最常用)
MyDel1 m2 = F2; m2(10, "bbb");编译器自动推断,省略 new,直接赋值方法名。
方式3:绑定【实例方法】(必须 new 对象)
MyDel2 m3 = new MyDel2(new Test().Add); Console.WriteLine(m3(10, 20));非静态方法属于对象,必须通过对象.方法名绑定。
方式4:实例方法简写绑定
MyDel2 m4 = new Test().Add; Console.WriteLine(m4(30, 40));五、委托两种调用方式
1. 简写调用(直接括号调用)
m4(30, 40);2. 官方原生调用 Invoke()
m4.Invoke(10, 20);本质:委托变量() 是 Invoke() 的语法糖,底层都是执行 Invoke。
六、委托空安全调用(面试高频)
MyDel2 m5 = null; //传统判断 if (m5 != null) { m5(10, 99); } //极简写法:空条件运算符 ?. m5?.Invoke(10, 20);原理:
如果委托变量为 null,不执行调用;
如果不为 null,自动执行 Invoke 调用方法。
开发强制规范:所有委托调用必须做空判断,防止空指针报错
七、直接调用 VS 委托间接调用区别
//1. 直接调用 F1(10, "sss"); new Test().Add(56, 90); //2. 委托间接调用 m1(10, "aaa"); m4(30, 40);直接调用:写死方法,无法灵活替换
委托调用:方法可动态替换、可当参数传递、实现解耦和回调
八、数组高阶函数拓展(Lambda+委托应用)
所有 Array 高阶函数,本质都是接收委托参数,Lambda 是委托的简写形式。
int[] arr = { 1, 2, 3 }; Array.Find(arr, v => v % 2 == 0); //查找第一个匹配元素 Array.FindIndex(arr, v => v % 2 == 0); //查找第一个匹配下标 Array.FindAll(arr, v => v % 2 == 0); //查找所有匹配元素 Array.TrueForAll(arr, v => v % 2 == 0); //判断是否全部满足条件 Array.Exists(arr, v => v % 2 == 0); //判断是否存在满足条件 Array.ForEach(arr, v => Console.WriteLine(v)); //遍历所有元素九、终极总结(简答题满分)
1. 委托是什么?
委托是一种引用类型,用于存储、绑定、传递方法,可以间接调用方法,常用于回调函数。
2. 绑定静态方法 vs 实例方法区别?
静态方法:直接 委托变量 = 方法名
实例方法:必须 通过对象.方法名 进行绑定
3. 委托安全调用规范?
使用委托?.Invoke()做空判断,避免空引用异常。
4. Invoke作用?
执行委托中绑定的方法,是委托调用的本质方法。
十、背诵口诀
委托引用存方法,签名一致才能绑
静态直接写方法,实例需要对象找
括号调用是简写,Invoke是原生宝
空判断不能少,问号Invoke最稳妥
C# 委托绑定与调用 核心易错点清单(考试/面试/开发避坑)
一、委托绑定 5 大易错点
1. 签名不匹配报错(最高频)
错误现象:绑定方法与委托的返回值、参数个数、参数类型不一致,直接编译报错。
易错场景:委托是双参数,绑定单参数方法;委托有返回值,绑定void方法。
正确规则:委托与目标方法返回值、参数数量、参数类型、参数顺序必须完全一致。
2. 绑定实例方法 忘记实例化对象
错误写法:直接绑定非静态方法MyDel2 m = Test.Add;
报错原因:实例方法属于对象,不属于类,不能直接通过类名访问。
正确写法:MyDel2 m = new Test().Add;
3. 混淆静态方法与实例方法绑定规则
静态方法:无需实例对象,直接赋值方法名即可绑定。
实例方法:必须依托具体对象,否则无法绑定、编译失败。
4. 委托重复赋值 覆盖之前绑定的方法
易错认知:普通赋值 = 会覆盖原有方法,不会累加。
区分:单播委托用 = 覆盖;多播委托用 += 叠加绑定多个方法。
5. 委托初始为null 直接调用报错
高危报错:未绑定任何方法的委托变量默认是null,直接m()或m.Invoke()报空引用异常。
规避方案:必须做空判断,优先使用m?.Invoke()极简安全写法。
二、委托调用 4 大易错点
1. 混淆直接调用与委托间接调用
直接调用:写死方法名,无法灵活替换,无复用性。
委托调用:通过委托变量间接执行,支持动态替换方法、回调传参,核心优势是解耦。
2. 忘记委托调用本质是 Invoke()
易错点:认为m(参数)是独立语法。
真相:括号调用是语法糖,底层本质都是执行Invoke()方法。
3. 调用参数数量/类型不匹配
绑定成功不代表调用正确,调用时传入参数和委托定义参数不一致,会直接编译报错。
例:委托定义双int参数,调用只传一个参数,语法报错。
4. 多播委托调用异常难以排查
多个方法绑定同一个委托,只要其中一个方法报错,整体调用直接终止,新手极易忽略。
三、语法简写易错点(高频坑)
1. 委托实例化简写乱用
标准写法:MyDel m = new MyDel(方法名);
简写写法:MyDel m = 方法名;
易错点:新手只记简写,不懂底层实例化原理,遇到复杂委托场景报错不会排查。
2. 混淆系统委托与自定义委托
Func:有返回值,最后一个泛型是返回值类型(极易写反参数和返回值)。
Action:无返回值,只传参数类型。
自定义delegate:完全自定义签名,不受系统委托限制。
四、考试/面试高频错题总结
委托可以绑定任意方法(❌错,必须签名完全一致)
实例方法可以直接通过类名绑定委托(❌错,必须new对象)
委托变量可以直接调用,无需判空(❌错,会空指针报错)
m() 和 m.Invoke() 是完全不同的方法(❌错,语法糖与原生关系)
单播委托赋值可以叠加多个方法(❌错,必须用+=多播)
五、终极避坑口诀
绑定先看签名对,实例必须对象配
默认null值别忘记,调用必做空判断位
单等覆盖多等加,Invoke才是原生类