-
事件驱动编程——C#开发实时消息通知系统
第一部分:C#基础入门
事件驱动编程——实时消息通知系统
实例介绍
事件驱动编程是响应式系统的核心范式,它通过“发布-订阅”模式实现组件间的解耦:当某个事件发生时(如用户登录、消息发送),系统自动通知所有订阅该事件的组件,无需主动轮询。本节通过实时消息通知系统的场景,展示事件驱动如何实vb.net教程C#教程python教程SQL教程access 2010教程现消息的实时推送(如邮件、短信、APP推送),让你掌握事件驱动的核心思想与实践技巧。
需求分析
设计一个模拟社交APP的实时消息通知系统,核心需求如下:
1.核心事件:
1.用户登录事件(UserLoggedIn):用户登录时触发;
2.消息发送事件(MessageSent):用户发送消息时触发;
2.通知渠道:
1.邮件通知:发送登录提醒或消息通知邮件;
2.短信通知:发送验证码或消息提醒短信;
3.APP推送:发送实时消息推送(如红点提示);
3.事件特性:
1.支持多订阅者(同一事件可绑定多个通知渠道);
2.支持事件取消订阅;
3.事件参数传递(如消息内容、发送者/接收者信息);
4.异常处理:单个通知渠道故障不影响其他渠道。
代码实现
-
核心模型与事件参数
csharp
using System;
// 用户模型
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string DeviceToken { get; set; } // APP推送设备令牌
}
// 消息模型
public class Message
{
public int Id { get; set; }
public User Sender { get; set; }
public User Receiver { get; set; }
public string Content { get; set; }
public DateTime SentTime { get; set; }
}
// 自定义事件参数:消息发送事件(继承EventArgs,符合.NET事件设计规范)
public class MessageSentEventArgs : EventArgs
{
public Message Message { get; }
public bool IsUrgent { get; } // 是否紧急消息
public MessageSentEventArgs(Message message, bool isUrgent = false)
{
Message = message;
IsUrgent = isUrgent;
}
}
// 自定义事件参数:用户登录事件
public class UserLoggedInEventArgs : EventArgs
{
public User User { get; }
public DateTime LoginTime { get; }
public UserLoggedInEventArgs(User user)
{
User = user;
LoginTime = DateTime.Now;
}
}
-
消息服务类(事件发布者)
csharp
// 消息服务:负责事件的发布(触发)
public class MessageService
{
// 事件定义:用户登录事件(使用EventHandler<T>泛型委托,T为事件参数)
public event EventHandler<UserLoggedInEventArgs> OnUserLoggedIn;
// 事件定义:消息发送事件
public event EventHandler<MessageSentEventArgs> OnMessageSent;
// 用户登录方法:触发登录事件
public void UserLogin(User user)
{
Console.WriteLine($"
=== 用户{user.Name}登录成功 ===");
// 触发事件:检查是否有订阅者,避免空引用
OnUserLoggedIn?.Invoke(this, new UserLoggedInEventArgs(user));
}
// 发送消息方法:触发消息发送事件
public void SendMessage(Message message, bool isUrgent = false)
{
Console.WriteLine($"
=== 消息发送:{message.Sender.Name} → {message.Receiver.Name} ===");
// 触发事件:传递自定义参数
OnMessageSent?.Invoke(this, new MessageSentEventArgs(message, isUrgent));
}
}
-
通知处理器(事件订阅者)
csharp
// 通知处理器:负责事件的订阅与处理
public class NotificationHandler
{
// 邮件通知处理方法
public void HandleEmailNotification(object sender, EventArgs e)
{
switch (e)
{
case UserLoggedInEventArgs loginArgs:
Console.WriteLine($"[邮件通知] 欢迎{loginArgs.User.Name}登录!登录时间:{loginArgs.LoginTime:yyyy-MM-dd HH:mm}");
break;
case MessageSentEventArgs msgArgs:
var msg = msgArgs.Message;
Console.WriteLine($"[邮件通知] {msg.Sender.Name}给您发送了消息:{msg.Content}({(msgArgs.IsUrgent ? "紧急" : "普通")})");
break;
}
}
// 短信通知处理方法
public void HandleSmsNotification(object sender, MessageSentEventArgs e)
{
if (e.IsUrgent) // 仅紧急消息发送短信
{
var receiver = e.Message.Receiver;
Console.WriteLine($"[短信通知] 您收到{sender.GetType().Name}的紧急消息:{e.Message.Content},请立即查看!");
}
}
// APP推送通知处理方法
public void HandleAppPushNotification(object sender, EventArgs e)
{
if (e is MessageSentEventArgs msgArgs)
{
var receiver = msgArgs.Message.Receiver;
Console.WriteLine($"[APP推送] 您有新消息来自{msgArgs.Message.Sender.Name} → {msgArgs.Message.Content.Substring(0, 10)}...");
}
}
}
-
测试程序
csharp
class Program
{
static void Main(string[] args)
{
// 1. 创建实例
var messageService = new MessageService();
var notificationHandler = new NotificationHandler();
// 2. 订阅事件
// 登录事件订阅邮件通知
messageService.OnUserLoggedIn += notificationHandler.HandleEmailNotification;
// 消息发送事件订阅多个通知渠道
messageService.OnMessageSent += notificationHandler.HandleEmailNotification;
messageService.OnMessageSent += notificationHandler.HandleSmsNotification;
messageService.OnMessageSent += notificationHandler.HandleAppPushNotification;
// 3. 模拟用户登录(触发登录事件)
var user1 = new User { Id = 1, Name = "张三", Email = "zhangsan@example.com", Phone = "13800138000", DeviceToken = "device_123" };
messageService.UserLogin(user1);
// 4. 模拟发送普通消息(触发消息事件)
var user2 = new User { Id = 2, Name = "李四", Email = "lisi@example.com", Phone = "13900139000", DeviceToken = "device_456" };
var message = new Message
{
Id = 1,
Sender = user1,
Receiver = user2,
Content = "明天一起去图书馆吗?",
SentTime = DateTime.Now
};
messageService.SendMessage(message);
// 5. 模拟发送紧急消息(触发消息事件)
var urgentMessage = new Message
{
Id = 2,
Sender = user2,
Receiver = user1,
Content = "紧急:明天图书馆闭馆!",
SentTime = DateTime.Now
};
messageService.SendMessage(urgentMessage, isUrgent: true);
// 6. 取消订阅:移除短信通知
messageService.OnMessageSent -= notificationHandler.HandleSmsNotification;
Console.WriteLine("
=== 取消短信通知后,再次发送消息 ===");
messageService.SendMessage(new Message
{
Id =3,
Sender=user1,
Receiver=user2,
Content="收到,谢谢提醒!",
SentTime=DateTime.Now
});
}
}
逐行讲解
-
事件参数设计
继承EventArgs:自定义事件参数需继承EventArgs(.NET事件设计规范),确保兼容性;
传递上下文:MessageSentEventArgs包含消息对象、紧急状态等信息,让订阅者获取足够的事件上下文; -
事件发布者(MessageService)
事件定义:使用EventHandler泛型委托(T为事件参数),符合.NET标准;
触发事件:OnUserLoggedIn?.Invoke(this, args)——?.避免空引用(无订阅者时不执行),Invoke传递事件源(this)和参数; -
事件订阅者(NotificationHandler)
多类型处理:HandleEmailNotification通过switch处理不同事件参数,实现通用通知;
条件处理:HandleSmsNotification仅处理紧急消息,体现事件驱动的灵活性; -
事件订阅与取消
订阅:messageService.OnMessageSent += handler——绑定事件处理器;
取消订阅:messageService.OnMessageSent -= handler——移除绑定,避免内存泄漏; -
测试程序
模拟场景:覆盖登录、普通消息、紧急消息、取消订阅等场景;
结果验证:紧急消息触发短信通知,取消订阅后短信不再发送,验证事件机制的正确性。
基础知识拓展 -
事件驱动核心思想
发布-订阅模式:发布者(事件源)触发事件,订阅者(处理器)响应事件,组件解耦;
实时响应:事件发生时立即通知,无需轮询(对比轮询:浪费资源、延迟高); -
.NET事件设计规范
事件命名:用OnXXX(如OnMessageSent)表示事件;
委托选择:优先使用EventHandler(T:EventArgs),避免自定义委托;
参数传递:事件参数需继承EventArgs,传递事件上下文; -
多播事件关键特性
执行顺序:按订阅顺序执行事件处理器;
异常处理:单个处理器抛出异常会中断后续执行(建议在处理器内捕获异常);
取消订阅:必须保存处理器引用(如notificationHandler.HandleSmsNotification)才能取消; -
异步事件处理
问题:同步事件处理器阻塞主线程(如发送邮件耗时);
解决方案:使用async void(仅用于事件处理器)或IAsyncEventHandler:
csharp
// 异步邮件通知处理器
public async void HandleEmailNotificationAsync(object sender, EventArgs e)
{
if (e is MessageSentEventArgs msgArgs)
{
await SendEmailAsync(msgArgs.Message.Receiver.Email, msgArgs.Message.Content);
}
}
// 订阅异步处理器
messageService.OnMessageSent += HandleEmailNotificationAsync;
注意:async void的异常无法通过try-catch捕获,需在处理器内处理;
- 事件驱动vs轮询
| 特性 | 事件驱动 | 轮询 |
|---|---|---|
| 实时性 | 高(事件发生立即响应) | 低(依赖轮询间隔) |
| 资源消耗 | 低(无事件时无操作) | 高(持续检查状态) |
| 耦合度 | 低(发布者与订阅者解耦) | 高(需直接访问状态) |
| 适用场景 | 实时通知、系统告警 | 状态变化缓慢的场景 |
总结
本节通过实时消息通知系统,展示了事件驱动编程的核心实践:事件定义→订阅→触发→响应。事件驱动实现了组件解耦、实时响应,是构建高并发、低延迟系统的关键技术。
重点掌握:
.NET事件设计规范(EventHandler
事件订阅/取消、触发的正确方式;
多播事件的异常处理与异步优化;
事件驱动是C#开发的必备技能,广泛应用于UI框架(如WPF、WinForms)、消息队列(如RabbitMQ)、实时系统(如IoT告警)等场景。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49425.html










