📅 Day 13:委托(Delegate)与事件(Event)
✅ 目标:
- 理解什么是委托(Delegate),它是如何实现函数回调的;
- 掌握使用
Action
和Func
泛型委托简化代码; - 学会定义和使用自定义委托;
- 理解什么是事件(Event),以及它在 GUI 编程、模块通信中的作用;
- 能够编写一个基于事件机制的程序,例如按钮点击模拟器。
🔁 一、委托(Delegate)基础
💡 什么是委托?
委托(Delegate) 是一种类型安全的“函数指针”,它可以引用一个或多个方法,并在运行时动态调用这些方法。委托是 C# 中实现回调机制的基础。
委托非常适合用于事件处理、异步编程、插件系统等场景。
📦 示例 1:定义并使用一个简单委托
// 定义一个委托,表示没有返回值、有一个字符串参数的方法
public delegate void MessageHandler(string message);class Program
{static void Main(){// 创建委托实例,绑定到具体方法MessageHandler handler = ShowMessage;// 调用委托handler("Hello, 委托世界!");}static void ShowMessage(string msg){Console.WriteLine(msg);}
}
🔄 示例 2:多播委托(Multicast Delegate)
委托可以绑定多个方法,形成一个调用链:
MessageHandler handler = ShowMessage;
handler += LogMessage; // 添加另一个方法handler("测试多播委托");void LogMessage(string msg)
{Console.WriteLine($"日志记录:{msg}");
}
输出:
Hello, 委托世界!
测试多播委托
日志记录:测试多播委托
⚙️ 二、泛型委托:Action
与 Func
为了简化常见委托的定义,C# 提供了两个内置泛型委托:
类型 | 返回值 | 参数数量 |
---|---|---|
Action | void | 最多 16 个参数 |
Func<T> | 有返回值 | 最多 16 个参数 + 一个返回值 |
💡 示例 1:使用 Action
Action<string> greet = name => Console.WriteLine($"你好,{name}!");
greet("小明");
💡 示例 2:使用 Func
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 5);
Console.WriteLine("结果:" + result); // 输出:8
🎉 三、事件(Event)
💡 什么是事件?
事件(Event) 是基于委托的封装机制,常用于对象之间的通信,特别是在 GUI 应用中(如按钮点击、窗口关闭等)。
事件遵循“发布-订阅”模型:一个对象发布事件,其他对象可以订阅该事件并做出响应。
📦 示例:实现一个按钮点击事件
public class Button
{// 定义事件,使用预定义的 EventHandler 委托public event EventHandler Click;// 模拟点击按钮public void OnClick(){Console.WriteLine("按钮被点击了!");Click?.Invoke(this, EventArgs.Empty); // 触发事件}
}class Program
{static void Main(){Button btn = new Button();// 订阅事件btn.Click += Button_Clicked;// 模拟点击btn.OnClick();}static void Button_Clicked(object sender, EventArgs e){Console.WriteLine("事件已触发:按钮被按下!");}
}
输出:
按钮被点击了!
事件已触发:按钮被按下!
🧩 四、自定义事件参数(Event Arguments)
如果你想传递更多数据给事件处理器,可以继承 EventArgs
并添加自定义字段。
💡 示例:传递鼠标坐标信息
public class MouseEventArgs : EventArgs
{public int X { get; set; }public int Y { get; set; }
}public class Mouse
{public event EventHandler<MouseEventArgs> Move;public void OnMouseMove(int x, int y){MouseEventArgs args = new MouseEventArgs { X = x, Y = y };Move?.Invoke(this, args);}
}class Program
{static void Main(){Mouse mouse = new Mouse();mouse.Move += Mouse_Move;mouse.OnMouseMove(100, 200);}static void Mouse_Move(object sender, MouseEventArgs e){Console.WriteLine($"鼠标移动到坐标:({e.X}, {e.Y})");}
}
💪 实战练习
✅ 练习 1:实现一个简单的“闹钟”事件系统
功能要求:
- 定义一个
AlarmClock
类,包含一个Tick
事件; - 每隔一段时间触发一次事件;
- 主程序订阅该事件并打印时间。
public class AlarmClock
{public event EventHandler Tick;public void Start(){while (true){Thread.Sleep(1000); // 每秒触发一次Console.WriteLine("滴答...");Tick?.Invoke(this, EventArgs.Empty);}}
}class Program
{static void Main(){AlarmClock clock = new AlarmClock();clock.Tick += Clock_Tick;Console.WriteLine("闹钟开始工作...");clock.Start();}static void Clock_Tick(object sender, EventArgs e){Console.WriteLine($"当前时间:{DateTime.Now.ToLongTimeString()}");}
}
📝 小结
今天你学会了:
- 使用 委托(Delegate) 来引用和调用方法;
- 使用
Action
和Func
简化常用委托; - 定义和使用 事件(Event),理解其在对象间通信中的作用;
- 实现了一个基于事件的程序,如按钮点击、闹钟定时器等;
- 掌握了如何自定义事件参数,以便在事件中传递更多信息。
这些技能将帮助你在开发图形界面应用、异步任务、插件系统等领域大显身手!
🧩 下一步学习方向(Day 14)
明天我们将进入一个新的主题 —— Lambda 表达式与表达式树(Expression Trees),它们是现代 C# 开发中非常重要的特性,尤其与 LINQ、反射、动态编译等密切相关。