作为一名.NET开发者,你是否还在为复杂的事件订阅管理而头疼?是否因为传统事件机制导致的内存泄漏而困扰?今天我要为你介绍一个革命性的解决方案——Easy.MessageHub,一个轻量级、高性能的消息传递框架,让你彻底摆脱传统事件的束缚!
本文将通过一个完整的工业监控系统示例,带你深入了解如何用Easy.MessageHub构建优雅的消息驱动架构,解决传统事件机制的痛点。这个算是我看到最简单的事件总线三方库了,值得学习一下。
C#// 传统事件容易忘记取消订阅
public class SensorService
{
public event EventHandler<TemperatureEventArgs> TemperatureChanged;
// 如果忘记取消订阅,就会内存泄漏!
}
发布者和订阅者之间必须有直接引用关系,违背了低耦合原则。
需要手动管理事件的订阅和取消订阅,代码繁琐且容易出错。
Easy.MessageHub采用发布-订阅模式,提供了以下核心优势:

让我们通过一个完整的工业监控系统来展示Easy.MessageHub的强大功能。
C#AppMessageHub/
├── Messages/ # 消息定义
├── Services/ # 业务服务
├── Forms/ # UI界面
└── Program.cs # 入口文件
C#// Messages/TemperatureMessage.cs
public class TemperatureMessage
{
public double Temperature { get; set; }
public string SensorId { get; set; }
public DateTime Timestamp { get; set; }
// 智能判断温度是否正常
public bool IsNormal => Temperature >= 15 && Temperature <= 85;
}
// Messages/AlarmMessage.cs
public class AlarmMessage
{
public string Message { get; set; }
public AlarmLevel Level { get; set; }
public DateTime Timestamp { get; set; }
public string Source { get; set; }
}
public enum AlarmLevel
{
Info,
Warning,
Critical
}
💡 设计要点:消息类应该是简单的POCO类,包含所有相关数据和业务逻辑。
C#// Services/SensorService.cs
public class SensorService
{
private readonly IMessageHub _messageHub;
private readonly Random _random;
private Timer _temperatureTimer;
public SensorService(IMessageHub messageHub)
{
_messageHub = messageHub;
_random = new Random();
}
public void StartMonitoring()
{
_temperatureTimer = new Timer(GenerateTemperatureData, null, 0, 2000);
}
private void GenerateTemperatureData(object state)
{
double temperature;
// 10%概率生成异常温度,用于测试告警
if (_random.NextDouble() < 0.1)
{
temperature = _random.NextDouble() < 0.5
? 100 + _random.NextDouble() * 50 // 过高温度
: -30 + _random.NextDouble() * 10; // 过低温度
}
else
{
// 正常温度范围:15-85°C
temperature = 15 + _random.NextDouble() * 70;
}
// 🔥 关键:发布消息,无需知道谁在监听
_messageHub.Publish(new TemperatureMessage
{
Temperature = Math.Round(temperature, 1),
SensorId = "TEMP_01",
Timestamp = DateTime.Now
});
}
}
C#// Services/AlarmService.cs
public class AlarmService : IDisposable
{
private readonly IMessageHub _messageHub;
private readonly List<Guid> _subscriptions = new List<Guid>();
public AlarmService(IMessageHub messageHub)
{
_messageHub = messageHub;
SubscribeToMessages();
}
private void SubscribeToMessages()
{
// 🔥 关键:订阅温度消息,自动监控异常
_subscriptions.Add(
_messageHub.Subscribe<TemperatureMessage>(OnTemperatureReceived)
);
}
private void OnTemperatureReceived(TemperatureMessage message)
{
if (!message.IsNormal)
{
var level = message.Temperature > 100
? AlarmLevel.Critical
: AlarmLevel.Warning;
var alarmMessage = message.Temperature > 100
? $"🔥 温度过高警报: {message.Temperature}°C"
: $"⚠️ 温度异常: {message.Temperature}°C";
// 发布告警消息
_messageHub.Publish(new AlarmMessage
{
Message = alarmMessage,
Level = level,
Timestamp = DateTime.Now,
Source = message.SensorId
});
}
}
public void Dispose()
{
// 正确的资源清理
foreach (var subscriptionId in _subscriptions)
{
_messageHub.Unsubscribe(subscriptionId);
}
_subscriptions.Clear();
}
}
C#using AppMessageHub.Messages;
using AppMessageHub.Services;
using Easy.MessageHub;
using System.Media;
namespace AppMessageHub
{
public partial class FrmMain : Form
{
private readonly IMessageHub _messageHub;
private readonly SensorService _sensorService;
private readonly AlarmService _alarmService;
private readonly List<Guid> _subscriptions = new List<Guid>();
private int _messageCount = 0;
private bool _isMonitoring = false;
public FrmMain()
{
InitializeComponent();
// 初始化MessageHub
_messageHub = new MessageHub();
// 初始化服务
_sensorService = new SensorService(_messageHub);
_alarmService = new AlarmService(_messageHub);
// 订阅消息
SubscribeToMessages();
// 绑定事件
BindEvents();
InitializeUI();
}
private void SubscribeToMessages()
{
// 使用Subscribe方法并收集订阅句柄
_subscriptions.Add(_messageHub.Subscribe<TemperatureMessage>(OnTemperatureMessageReceived));
_subscriptions.Add(_messageHub.Subscribe<PressureMessage>(OnPressureMessageReceived));
_subscriptions.Add(_messageHub.Subscribe<AlarmMessage>(OnAlarmMessageReceived));
_subscriptions.Add(_messageHub.Subscribe<SystemStatusMessage>(OnSystemStatusMessageReceived));
}
private void BindEvents()
{
btnStart.Click += BtnStart_Click;
btnStop.Click += BtnStop_Click;
btnClearAlarms.Click += BtnClearAlarms_Click;
btnClearLog.Click += BtnClearLog_Click;
this.FormClosing += FrmMain_FormClosing;
}
private void InitializeUI()
{
lblTempValue.Text = "--.-";
lblPressureValue.Text = "--.--";
lblTempStatus.Text = "状态: 离线";
lblPressureStatus.Text = "状态: 离线";
pbTempIndicator.BackColor = Color.Gray;
pbPressureIndicator.BackColor = Color.Gray;
AddMessageToLog("系统初始化完成", Color.Cyan);
AddMessageToLog("等待启动监控...", Color.Yellow);
}
private void BtnStart_Click(object sender, EventArgs e)
{
StartMonitoring();
}
private void BtnStop_Click(object sender, EventArgs e)
{
StopMonitoring();
}
private void BtnClearAlarms_Click(object sender, EventArgs e)
{
lstAlarms.Items.Clear();
AddMessageToLog("告警列表已清空", Color.Orange);
}
private void BtnClearLog_Click(object sender, EventArgs e)
{
rtbMessageLog.Clear();
_messageCount = 0;
UpdateMessageCount();
}
private void StartMonitoring()
{
if (_isMonitoring) return;
_isMonitoring = true;
_sensorService.StartMonitoring();
btnStart.Enabled = false;
btnStop.Enabled = true;
lblSystemStatus.Text = "系统状态: 运行中";
lblSystemStatus.ForeColor = Color.Green;
lblStatusMessage.Text = "监控已启动";
// 发布系统状态消息
_messageHub.Publish(new SystemStatusMessage
{
Status = SystemStatus.Running,
Description = "系统监控已启动",
Timestamp = DateTime.Now
});
AddMessageToLog("=== 系统监控已启动 ===", Color.Green);
}
private void StopMonitoring()
{
if (!_isMonitoring) return;
_isMonitoring = false;
_sensorService.StopMonitoring();
btnStart.Enabled = true;
btnStop.Enabled = false;
lblSystemStatus.Text = "系统状态: 已停止";
lblSystemStatus.ForeColor = Color.Orange;
lblStatusMessage.Text = "监控已停止";
// 重置传感器显示
lblTempValue.Text = "--.-";
lblPressureValue.Text = "--.--";
lblTempStatus.Text = "状态: 离线";
lblPressureStatus.Text = "状态: 离线";
pbTempIndicator.BackColor = Color.Gray;
pbPressureIndicator.BackColor = Color.Gray;
// 发布系统状态消息
_messageHub.Publish(new SystemStatusMessage
{
Status = SystemStatus.Stopped,
Description = "系统监控已停止",
Timestamp = DateTime.Now
});
AddMessageToLog("=== 系统监控已停止 ===", Color.Red);
}
private void OnTemperatureMessageReceived(TemperatureMessage message)
{
if (InvokeRequired)
{
Invoke(new Action(() => OnTemperatureMessageReceived(message)));
return;
}
if (!chkShowTemp.Checked) return;
lblTempValue.Text = message.Temperature.ToString("F1");
lblTempStatus.Text = message.IsNormal ? "状态: 正常" : "状态: 异常";
lblTempStatus.ForeColor = message.IsNormal ? Color.Green : Color.Red;
pbTempIndicator.BackColor = message.IsNormal ? Color.Green : Color.Red;
// 添加到日志
var color = message.IsNormal ? Color.LightGreen : Color.Yellow;
var status = message.IsNormal ? "正常" : "异常";
AddMessageToLog($"[温度] {message.SensorId}: {message.Temperature:F1}°C ({status}) - {message.Timestamp:HH:mm:ss.fff}", color);
}
private void OnPressureMessageReceived(PressureMessage message)
{
if (InvokeRequired)
{
Invoke(new Action(() => OnPressureMessageReceived(message)));
return;
}
if (!chkShowPressure.Checked) return;
lblPressureValue.Text = message.Pressure.ToString("F2");
lblPressureStatus.Text = message.IsNormal ? "状态: 正常" : "状态: 异常";
lblPressureStatus.ForeColor = message.IsNormal ? Color.Green : Color.Red;
pbPressureIndicator.BackColor = message.IsNormal ? Color.Green : Color.Red;
// 添加到日志
var color = message.IsNormal ? Color.LightBlue : Color.Yellow;
var status = message.IsNormal ? "正常" : "异常";
AddMessageToLog($"[压力] {message.SensorId}: {message.Pressure:F2} bar ({status}) - {message.Timestamp:HH:mm:ss.fff}", color);
}
private void OnAlarmMessageReceived(AlarmMessage message)
{
if (InvokeRequired)
{
Invoke(new Action(() => OnAlarmMessageReceived(message)));
return;
}
if (!chkShowAlarms.Checked) return;
var alarmText = $"[{message.Timestamp:HH:mm:ss}] [{message.Level}] {message.Message} (来源: {message.Source})";
lstAlarms.Items.Insert(0, alarmText);
if (lstAlarms.Items.Count > 100)
{
lstAlarms.Items.RemoveAt(lstAlarms.Items.Count - 1);
}
var color = message.Level switch
{
AlarmLevel.Info => Color.White,
AlarmLevel.Warning => Color.Orange,
AlarmLevel.Critical => Color.Red,
_ => Color.White
};
AddMessageToLog($"[告警-{message.Level}] {message.Message} (来源: {message.Source}) - {message.Timestamp:HH:mm:ss.fff}", color);
// 发出提示音
if (message.Level == AlarmLevel.Critical)
{
SystemSounds.Exclamation.Play();
}
}
private void OnSystemStatusMessageReceived(SystemStatusMessage message)
{
if (InvokeRequired)
{
Invoke(new Action(() => OnSystemStatusMessageReceived(message)));
return;
}
AddMessageToLog($"[系统] {message.Description} - 状态: {message.Status} - {message.Timestamp:HH:mm:ss.fff}", Color.Cyan);
}
private void AddMessageToLog(string message, Color color)
{
if (rtbMessageLog.Lines.Count() > 1000)
{
rtbMessageLog.Clear();
rtbMessageLog.SelectionColor = Color.Gray;
rtbMessageLog.AppendText("=== 日志已清理,避免内存溢出 ===\n");
}
rtbMessageLog.SelectionStart = rtbMessageLog.TextLength;
rtbMessageLog.SelectionLength = 0;
rtbMessageLog.SelectionColor = color;
rtbMessageLog.AppendText(message + Environment.NewLine);
rtbMessageLog.SelectionColor = rtbMessageLog.ForeColor;
rtbMessageLog.ScrollToCaret();
_messageCount++;
UpdateMessageCount();
}
private void UpdateMessageCount()
{
lblMessageCount.Text = $"消息计数: {_messageCount}";
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
StopMonitoring();
// 取消所有订阅
foreach (var subscriptionId in _subscriptions)
{
_messageHub.Unsubscribe(subscriptionId);
}
_subscriptions.Clear();
// 释放服务
_alarmService?.Dispose();
// 释放MessageHub
if (_messageHub is IDisposable disposableHub)
{
disposableHub.Dispose();
}
}
}
}

| 特性 | 传统事件 | Easy.MessageHub |
|---|---|---|
| 内存安全 | ❌ 容易泄漏 | ✅ 弱引用机制 |
| 代码耦合 | ❌ 强耦合 | ✅ 完全解耦 |
| 线程安全 | ❌ 需手动处理 | ✅ 天然线程安全 |
| 生命周期 | ❌ 复杂管理 | ✅ 自动管理 |
| 类型安全 | ✅ 支持 | ✅ 强类型支持 |
消息类设计原则
C#// 好的消息类:包含完整上下文信息
public class OrderCreatedMessage
{
public string OrderId { get; set; }
public DateTime CreatedAt { get; set; }
public decimal Amount { get; set; }
public string CustomerId { get; set; }
}
正确的资源清理
C#public void Dispose()
{
foreach (var subscription in _subscriptions)
{
_messageHub.Unsubscribe(subscription);
}
}
C#// 使用消息过滤避免不必要的处理
_messageHub.Subscribe<TemperatureMessage>(msg =>
{
if (msg.SensorId == "TEMP_01") // 只处理特定传感器
{
ProcessTemperature(msg);
}
});
当你运行这个监控系统时,你会看到:
Easy.MessageHub不仅仅是一个消息传递框架,更是一种现代化的架构思维。它让我们的C#应用变得更加优雅、安全、高效。
💡 金句总结:
你在项目中是否遇到过传统事件机制的痛点?使用MessageHub后有什么新的体验?欢迎在评论区分享你的开发经验!
如果这篇文章对你有帮助,请转发给更多需要的同行,让我们一起构建更优雅的C#应用!
🔖 收藏级代码模板已整理完毕,记得保存备用!
相关信息
通过网盘分享的文件:AppMessageHub.zip 链接: https://pan.baidu.com/s/1DwH2_odCXCvXa6ti50SISA?pwd=q26m 提取码: q26m --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!