知识全景思维导图一、 委托到底是什么通俗理解是把方法函数当作包裹交给这个代理人当你喊“执行”的时候代理人就会去调用这个方法。委托的“三步走”战略1. 声明定义契约// 定义一个契约我只能代理 [返回值为int接收两个int参数] 的方法 public delegate int MathOperation(int x, int y);2. 实例化绑定方法// 传统写法 MathOperation op1 new MathOperation(Add); // C# 2.0 简化写法 (语法糖) MathOperation op2 Add; // 绑定 Lambda 表达式 MathOperation op3 (x, y) x * y;3. 调用触发执行int result1 op1(3, 4); // 直接像方法一样调用 (常用) int result2 op1.Invoke(3, 4); // 使用 Invoke 方法调用注意:委托在编译时会严格校验方法签名确保类型匹配和调用安全public delegate void ProcessData(string input); // ✅ 合法绑定 ProcessData handler s Console.WriteLine(s); // ❌ 非法绑定 参数类型不匹配 编译错误 // ProcessData errorHandler (int i) Console.WriteLine(i); // ❌ 非法绑定 参数个数不匹配 编译错误 // ProcessData errorHandler1 (i,j) Console.WriteLine(i,j); // ❌ 非法绑定 返回值类型不匹配 编译错误 // ProcessData errorHandler2 s s;二、 为什么需要委托假设我们在开发一个游戏主界面有 6 个按钮开始游戏、排行榜、分享好友等。如果我们为每个按钮写一个单独的 StartButton、FriendButton 类代码会极度冗余。委托的解决方案只写一个 Button 类将“点击后干什么”交给外界决定例如class Button { public delegate void OnClickDelegate(); // 1. 定义委托类型 public OnClickDelegate? onClick null; // 2. 声明委托变量 public void Click() { Console.WriteLine(按钮被按下了...); onClick?.Invoke(); // 3. 如果有人绑定了方法就执行它 } } // 外界使用 Button startBtn new Button(); startBtn.Click();三、多播委托多播委托允许一个委托变量内部维护一个方法链表。当你调用这个委托时它会按照顺序把链表里的方法全执行一遍。将方法加入链表。-将方法移出链表。金典案例:小明让小张帮忙买水(1) 先定义一个买东西的类public class Zhang { public delegate void BuySomethingDelegate(); public void Buywater() { Console.WriteLine(买水); } public void BuyKFC() { Console.WriteLine(买肯德基); } public void BuyHotDog() { Console.WriteLine(买热狗); } }(2) 小张帮小明完成了买水的操作Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd(); //bsd.Invoke();(3) 小明突然想吃东西又让小张顺路带个热狗和肯德基Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd z.BuyHotDog; bsd z.BuyKFC; bsd();4还没付钱小明怕吃不下又让小明把热狗退了Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd z.BuyHotDog; bsd z.BuyKFC; bsd - z.BuyHotDog; bsd();多播委托的特点1. 调用顺序方法按照它们被添加的顺序调用2. 返回值如果委托有返回值只有最后一个方法的返回值会被保留3. 异常处理如果某个方法抛出异常后续方法不会被调用四、 微软的三大委托为了避免我们每次都要 public delegate void XXX()微软在 .NET 中直接帮我们提前定义好了三种最常用的泛型委托。委托名称特点适用场景签名示例ActionT...无返回值(最多支持16个参数)只需要执行动作不需要汇报结果Actionstring print s Console.WriteLine(s);FuncT..., TResult有返回值(最后一个泛型是返回值类型)需要计算并返回结果Funcint, int, int add (a, b) a b;PredicateT仅1个参数返回 bool条件判断、集合筛选 (Find, FindAll)Predicateint isEven n n % 2 0;五、 事件 (Event)1. 什么是事件事件本质上是一种特殊的多播委托。 它是基于“发布-订阅Pub/Sub”模型的。发布者 (Publisher)拥有事件的类决定何时触发事件。订阅者 (Subscriber)监听事件的类决定发生事件后做什么。案例// 发布者类 public class PublisherClass { // 和事件搭配的委托 public delegate void PubDelegate(); // 定义事件 public event PubDelegate? PubEvent; // 编写处理事件的具体逻辑 public void EventHandling() { if (PubEvent null) { Console.WriteLine(需要注册事件的啊); } else { // 执行注册的事件 PubEvent(); } } } // 订阅者类 public class SubscriberClass { public void PrintOut() { Console.WriteLine(执行了订阅者类中的事件。); Console.ReadLine(); } } internal class Class1 { static void Main(string[] args) { // 实例化对象 PublisherClass p new PublisherClass(); SubscriberClass s new SubscriberClass(); // 执行事件 p.EventHandling(); // 注册事件 p.PubEvent new PublisherClass.PubDelegate(s.PrintOut); //可以简写: //p.PubEvent s.PrintOut; // 执行事件 p.EventHandling(); } }2. 使用EventHandler 声明事件EventHandler 是 .NET 中最基本的事件委托其定义如下public delegate void EventHandler(object sender, EventArgs e); //sender触发事件的对象通常是 this。 //e事件参数如果不需要传递额外数据可以使用 EventArgs.Empty。案例//事件发布者 public class Button { // 1. 定义事件 public event EventHandler Click; // 2. 触发事件的方法遵循 .NET 规范通常命名为 OnXXX编写处理事件的具体逻辑 public virtual void OnClick(EventArgs e) { Click?.Invoke(this, e); // 安全调用避免 NullReferenceException } }EventHandler类型的事件可以通过运算符来订阅事件处理程序.有下面这几种写法(1) 使用 Lambda 表达式推荐简洁写法适用场景简单逻辑无需复用的事件处理。btn.Click (sender, e) { Console.WriteLine($事件触发者:{sender}); //事件触发者 Console.WriteLine($事件参数:{e}); Console.WriteLine(Click event handled!); };(2) 使用方法符合传统 .NET 风格适用场景需要复用的逻辑或复杂处理。btn.Click OnButtonClick; // 事件处理方法 private static void OnButtonClick(object sender, EventArgs e) { Console.WriteLine($事件触发者: {sender}, 参数: {e}); }六、 事件 vs 委托对比维度委托 (Delegate)事件 (Event)本质是一种类型Type像类一样是委托变量的一个包装器类似于属性包装了字段访问控制外部可以随意赋值 () 或清空外部只能订阅 () 或退订 (-)触发权限任何人拿到委托变量都可以 Invoke()只有声明事件的类自己才能触发 (Invoke)接口定义不能直接定义在接口中可以定义在接口中 (event EventHandler XXX;)主要用途灵活的方法传递、回调函数、LINQ查询严格的发布-订阅模式状态通知如 UI 交互总结委托是底层基础事件是基于委托做的高级封装为的是代码的安全和解耦。
C#学习笔记——委托
知识全景思维导图一、 委托到底是什么通俗理解是把方法函数当作包裹交给这个代理人当你喊“执行”的时候代理人就会去调用这个方法。委托的“三步走”战略1. 声明定义契约// 定义一个契约我只能代理 [返回值为int接收两个int参数] 的方法 public delegate int MathOperation(int x, int y);2. 实例化绑定方法// 传统写法 MathOperation op1 new MathOperation(Add); // C# 2.0 简化写法 (语法糖) MathOperation op2 Add; // 绑定 Lambda 表达式 MathOperation op3 (x, y) x * y;3. 调用触发执行int result1 op1(3, 4); // 直接像方法一样调用 (常用) int result2 op1.Invoke(3, 4); // 使用 Invoke 方法调用注意:委托在编译时会严格校验方法签名确保类型匹配和调用安全public delegate void ProcessData(string input); // ✅ 合法绑定 ProcessData handler s Console.WriteLine(s); // ❌ 非法绑定 参数类型不匹配 编译错误 // ProcessData errorHandler (int i) Console.WriteLine(i); // ❌ 非法绑定 参数个数不匹配 编译错误 // ProcessData errorHandler1 (i,j) Console.WriteLine(i,j); // ❌ 非法绑定 返回值类型不匹配 编译错误 // ProcessData errorHandler2 s s;二、 为什么需要委托假设我们在开发一个游戏主界面有 6 个按钮开始游戏、排行榜、分享好友等。如果我们为每个按钮写一个单独的 StartButton、FriendButton 类代码会极度冗余。委托的解决方案只写一个 Button 类将“点击后干什么”交给外界决定例如class Button { public delegate void OnClickDelegate(); // 1. 定义委托类型 public OnClickDelegate? onClick null; // 2. 声明委托变量 public void Click() { Console.WriteLine(按钮被按下了...); onClick?.Invoke(); // 3. 如果有人绑定了方法就执行它 } } // 外界使用 Button startBtn new Button(); startBtn.Click();三、多播委托多播委托允许一个委托变量内部维护一个方法链表。当你调用这个委托时它会按照顺序把链表里的方法全执行一遍。将方法加入链表。-将方法移出链表。金典案例:小明让小张帮忙买水(1) 先定义一个买东西的类public class Zhang { public delegate void BuySomethingDelegate(); public void Buywater() { Console.WriteLine(买水); } public void BuyKFC() { Console.WriteLine(买肯德基); } public void BuyHotDog() { Console.WriteLine(买热狗); } }(2) 小张帮小明完成了买水的操作Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd(); //bsd.Invoke();(3) 小明突然想吃东西又让小张顺路带个热狗和肯德基Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd z.BuyHotDog; bsd z.BuyKFC; bsd();4还没付钱小明怕吃不下又让小明把热狗退了Zhang z new Zhang(); BuySomethingDelegate bsd new BuySomethingDelegate(z.Buywater); bsd z.BuyHotDog; bsd z.BuyKFC; bsd - z.BuyHotDog; bsd();多播委托的特点1. 调用顺序方法按照它们被添加的顺序调用2. 返回值如果委托有返回值只有最后一个方法的返回值会被保留3. 异常处理如果某个方法抛出异常后续方法不会被调用四、 微软的三大委托为了避免我们每次都要 public delegate void XXX()微软在 .NET 中直接帮我们提前定义好了三种最常用的泛型委托。委托名称特点适用场景签名示例ActionT...无返回值(最多支持16个参数)只需要执行动作不需要汇报结果Actionstring print s Console.WriteLine(s);FuncT..., TResult有返回值(最后一个泛型是返回值类型)需要计算并返回结果Funcint, int, int add (a, b) a b;PredicateT仅1个参数返回 bool条件判断、集合筛选 (Find, FindAll)Predicateint isEven n n % 2 0;五、 事件 (Event)1. 什么是事件事件本质上是一种特殊的多播委托。 它是基于“发布-订阅Pub/Sub”模型的。发布者 (Publisher)拥有事件的类决定何时触发事件。订阅者 (Subscriber)监听事件的类决定发生事件后做什么。案例// 发布者类 public class PublisherClass { // 和事件搭配的委托 public delegate void PubDelegate(); // 定义事件 public event PubDelegate? PubEvent; // 编写处理事件的具体逻辑 public void EventHandling() { if (PubEvent null) { Console.WriteLine(需要注册事件的啊); } else { // 执行注册的事件 PubEvent(); } } } // 订阅者类 public class SubscriberClass { public void PrintOut() { Console.WriteLine(执行了订阅者类中的事件。); Console.ReadLine(); } } internal class Class1 { static void Main(string[] args) { // 实例化对象 PublisherClass p new PublisherClass(); SubscriberClass s new SubscriberClass(); // 执行事件 p.EventHandling(); // 注册事件 p.PubEvent new PublisherClass.PubDelegate(s.PrintOut); //可以简写: //p.PubEvent s.PrintOut; // 执行事件 p.EventHandling(); } }2. 使用EventHandler 声明事件EventHandler 是 .NET 中最基本的事件委托其定义如下public delegate void EventHandler(object sender, EventArgs e); //sender触发事件的对象通常是 this。 //e事件参数如果不需要传递额外数据可以使用 EventArgs.Empty。案例//事件发布者 public class Button { // 1. 定义事件 public event EventHandler Click; // 2. 触发事件的方法遵循 .NET 规范通常命名为 OnXXX编写处理事件的具体逻辑 public virtual void OnClick(EventArgs e) { Click?.Invoke(this, e); // 安全调用避免 NullReferenceException } }EventHandler类型的事件可以通过运算符来订阅事件处理程序.有下面这几种写法(1) 使用 Lambda 表达式推荐简洁写法适用场景简单逻辑无需复用的事件处理。btn.Click (sender, e) { Console.WriteLine($事件触发者:{sender}); //事件触发者 Console.WriteLine($事件参数:{e}); Console.WriteLine(Click event handled!); };(2) 使用方法符合传统 .NET 风格适用场景需要复用的逻辑或复杂处理。btn.Click OnButtonClick; // 事件处理方法 private static void OnButtonClick(object sender, EventArgs e) { Console.WriteLine($事件触发者: {sender}, 参数: {e}); }六、 事件 vs 委托对比维度委托 (Delegate)事件 (Event)本质是一种类型Type像类一样是委托变量的一个包装器类似于属性包装了字段访问控制外部可以随意赋值 () 或清空外部只能订阅 () 或退订 (-)触发权限任何人拿到委托变量都可以 Invoke()只有声明事件的类自己才能触发 (Invoke)接口定义不能直接定义在接口中可以定义在接口中 (event EventHandler XXX;)主要用途灵活的方法传递、回调函数、LINQ查询严格的发布-订阅模式状态通知如 UI 交互总结委托是底层基础事件是基于委托做的高级封装为的是代码的安全和解耦。