在 C# 编程中,委托和事件是实现回调机制和发布-订阅模式的核心技术。它们让对象之间能够进行松耦合的通信,是构建可扩展应用程序的重要工具。
1. 委托(Delegate)
1.1 委托的基本概念
委托是一种类型安全的函数指针,它定义了方法的签名,可以引用任何与其签名匹配的方法。
// 声明一个委托public delegate void MessageHandler(string message);
// 使用委托public class DelegateExample{
public static void ShowMessage(string msg)
{ Console.WriteLine($"信息: {msg}"); }
public static void LogMessage(string msg)
{ Console.WriteLine($"[日志] {DateTime.Now}: {msg}"); }
public static void Demo()
{ // 创建委托实例
MessageHandler handler = ShowMessage;
// 调用委托
handler("Hello World!");
// 多播委托 - 组合多个方法 handler += LogMessage;
handler("这是一个测试消息");
}}
1.2 实际应用场景:排序算法
public class SortExample{
// 定义比较委托 public delegate int CompareDelegate<T>(T
x, T y);
// 使用委托的冒泡排序 public static void BubbleSort<T>(T[]
array, CompareDelegate<T> comparer) {
for (int i = 0; i < array.Length - 1;
i++) {
for (int j = 0; j < array.Length - i - 1;
j++) {
if (comparer(array[j], array[j + 1])
> 0) {
// 交换元素
T temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
} } }
// 比较方法 public static int CompareInt(int x, int y)
{ return x.CompareTo(y);
}
public static int CompareString(string x, string y)
{ return string.Compare(x,
y); }
public static void Demo()
{ // 整数排序
int[] numbers = { 5, 2, 8, 1, 9 };
BubbleSort(numbers, CompareInt);
Console.WriteLine("排序后的数字: " + string.Join(",
", numbers));
// 字符串排序
string[] names = { "John", "Alice", "Bob", "Charlie" };
BubbleSort(names, CompareString);
Console.WriteLine("排序后的名字: " + string.Join(",
", names)); }}
2. 事件(Event)
2.1 事件的基本概念
事件是基于委托的特殊构造,提供了更好的封装性和安全性。事件遵循发布-订阅模式。
// 事件发布者public class Button{
// 1. 定义事件委托 public delegate void ClickEventHandler(object sender,
EventArgs e);
// 2. 声明事件 public event ClickEventHandler
Click;
// 3. 触发事件的方法 protected virtual void OnClick(EventArgs
e) { Click?.Invoke(this, e);
}
public void Press() {
Console.WriteLine("按钮被按下...");
OnClick(EventArgs.Empty); }}
// 事件订阅者public class UserInterface{
public void SubscribeToButton(Button button)
{ // 订阅事件
button.Click += OnButtonClick; }
private void OnButtonClick(object sender,
EventArgs e) { Console.WriteLine("UI:
按钮点击事件被处理"); }}
2.2 实际应用:温度监控系统
// 自定义事件参数public class TemperatureChangedEventArgs : EventArgs{
public double OldTemperature { get; }
public double NewTemperature { get; }
public DateTime ChangeTime { get; }
public TemperatureChangedEventArgs(double oldTemp, double newTemp)
{ OldTemperature = oldTemp;
NewTemperature = newTemp; ChangeTime =
DateTime.Now; }}
// 温度传感器(事件发布者)public class TemperatureSensor{
private double _currentTemperature;
// 使用 EventHandler<T> 简化事件声明 public event EventHandler<TemperatureChangedEventArgs>
TemperatureChanged;
public double CurrentTemperature
{ get => _currentTemperature;
set {
if (value != _currentTemperature)
{
double oldTemp = _currentTemperature;
_currentTemperature = value;
OnTemperatureChanged(oldTemp, value);
} } }
protected virtual void OnTemperatureChanged(double oldTemp, double newTemp)
{ TemperatureChanged?.Invoke(this,
new TemperatureChangedEventArgs(oldTemp,
newTemp)); }}
// 显示器(事件订阅者)public class Display{
public void SubscribeToSensor(TemperatureSensor sensor)
{ sensor.TemperatureChanged +=
OnTemperatureChanged; }
private void OnTemperatureChanged(object sender,
TemperatureChangedEventArgs e) {
Console.WriteLine($"显示器: 温度从 {e.OldTemperature}°C 变为 {e.NewTemperature}°C");
Console.WriteLine($"变化时间: {e.ChangeTime:HH:mm:ss}");
if (e.NewTemperature > 30)
{
Console.WriteLine("警告: 温度过高!"); }
else if (e.NewTemperature < 10)
{ Console.WriteLine("警告: 温度过低!");
} }}
// 数据记录器(另一个订阅者)public class DataLogger{
private readonly List<string> _log = new List<string>();
public void SubscribeToSensor(TemperatureSensor
sensor) { sensor.TemperatureChanged +=
OnTemperatureChanged; }
private void OnTemperatureChanged(object sender,
TemperatureChangedEventArgs e) { string logEntry
= $"{e.ChangeTime:yyyy-MM-dd HH:mm:ss} - " +
$"温度变化: {e.OldTemperature} -> {e.NewTemperature}°C";
_log.Add(logEntry);
Console.WriteLine($"数据记录: {logEntry}");
}
public void PrintLog() {
Console.WriteLine("\n=== 温度变化记录
==="); foreach (var entry in _log)
{ Console.WriteLine(entry);
} }}
2.3 完整演示程序
class Program{ static void Main(string[]
args) { Console.WriteLine("=== 委托演示 ==="); DelegateExample.Demo();
Console.WriteLine("\n=== 排序演示 ==="); SortExample.Demo();
Console.WriteLine("\n=== 温度监控系统演示 ===");
// 创建温度传感器
var sensor = new TemperatureSensor();
// 创建订阅者
var display = new Display();
var logger = new DataLogger();
// 订阅事件
display.SubscribeToSensor(sensor);
logger.SubscribeToSensor(sensor);
// 模拟温度变化
sensor.CurrentTemperature = 25.0;
sensor.CurrentTemperature = 28.5;
sensor.CurrentTemperature = 32.0; // 触发高温警告
sensor.CurrentTemperature = 15.0;
sensor.CurrentTemperature = 8.5; // 触发低温警告
// 显示记录
logger.PrintLog();
Console.WriteLine("\n=== 按钮事件演示 ==="); var button = new Button();
var ui = new UserInterface();
ui.SubscribeToButton(button);
button.Press();
Console.ReadLine(); }}
3. 委托和事件的高级用法
3.1 使用 Action 和 Func 委托
C# 提供了内置的泛型委托,可以避免自定义委托声明。
public class AdvancedDelegateExample{
public static void ProcessData(int[] data,
Action<int> processAction) {
foreach (var item in data)
{ processAction(item);
} }
public static List<TResult> TransformData<T, TResult>(
List<T> data, Func<T, TResult>
transformFunc) { var result
= new List<TResult>(); foreach (var item in data)
{
result.Add(transformFunc(item)); }
return result; }
public static void Demo()
{ // 使用 Action 委托 int[] numbers = { 1, 2, 3, 4, 5 };
ProcessData(numbers, x => Console.WriteLine($"处理数字: {x}"));
// 使用 Func 委托 var names = new List<string>
{ "apple", "banana", "cherry" };
var upperNames = TransformData(names, name =>
name.ToUpper());
Console.WriteLine("转换后的名字: " + string.Join(", ", upperNames));
}}
3.2 事件访问器
public class EventAccessorExample{
private EventHandler _myEvent;
public event EventHandler MyEvent
{ add {
Console.WriteLine("添加事件处理器"); _myEvent += value;
} remove
{ Console.WriteLine("移除事件处理器"); _myEvent -= value;
} }
protected virtual void OnMyEvent()
{ _myEvent?.Invoke(this,
EventArgs.Empty); }}
4. 最佳实践和注意事项
- 命名约定:事件处理委托以 EventHandler 结尾,事件参数以 EventArgs 结尾
- 线程安全的事件调用:
protected virtual void OnTemperatureChanged(double oldTemp, double newTemp){ var handler = TemperatureChanged; if (handler != null) { handler(this, new TemperatureChangedEventArgs(oldTemp, newTemp)); }}
- 及时取消订阅防止内存泄漏:
public void UnsubscribeFromSensor(TemperatureSensor sensor){ sensor.TemperatureChanged -= OnTemperatureChanged;}
总结
委托和事件是 C# 中强大的特性,它们:
- 委托:提供类型安全的回调机制,支持多播
- 事件:基于委托,提供更好的封装性和安全性
- 应用场景:GUI 编程、异步编程、插件系统、观察者模式等
- 优势:松耦合、可扩展、易于测试
通过合理使用委托和事件,可以构建出灵活、可维护的应用程序架构。
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号