C#完成一个应用内的消息中心

发布时间:2021-11-26

本文会讲解如何使用 C# 完成一个应用内部的消息中心(事件总线),事件驱动最大的好处就是可以很大程度的解耦合,松散结构。

模式介绍

简单来说就是一个发布订阅模式设计,对于消息的产生者来说,并不对直接将消息发送给消息的处理者,而是将消息发送给独立的消息中心,这里和观察者模式做个区别。对于消息产生者来说,无需知道有哪些订阅者。而对于订阅者来说,同样无需知道消息发布者的存在。

实现

使用 C# 实现如下,一个消息中心有两个方法,一个是发布消息:Send/Publish,有一个是订阅消息:Subscribe

public static class MessageCenter
{
    public static void Send(object sender, string name, object data)
    {
        InnerSend(sender, name, data);
    }
    
     public static void Subscribe<TSender, TData>(object subscriber, string name, Action<TSender, TData> action)
    {
        InnerSubscribe(subscriber, name, action?.Method, action?.Target);
    }
}

接着实现 InnerSend ,发布消息本质就是查询所有的订阅者,并执行订阅的响应事件

private static void InnerSend(object sender, string name, object data)
{
    if (string.IsNullOrEmpty(name))
        throw new NullReferenceException();
    if (subs.TryGetValue(name, out var subscriptions))
    {
        foreach (var subscription in subscriptions)
        {
            subscription.Invoke(sender, data);
        }
    }
}

然后是 InnerSubscribe,将订阅者添加到订阅集合里

private static void InnerSubscribe(object subscriber, string name, MethodInfo methodInfo, object target)
{
    if (subscriber == null)
        throw new NullReferenceException();
    if (string.IsNullOrEmpty(name))
        throw new NullReferenceException();
    var sub = new Subscription(subscriber, methodInfo, target);
    if (subs.ContainsKey(name))
    {
        subs[name].Add(sub);
        return;
    }
    subs.Add(name, new List<Subscription>() { sub });
}

接下来实现订阅类,他将订阅者规范成统一的类型,方便消息传递

class Subscription
{
    public Subscription(object source, MethodInfo methodInfo, object target)
    {
        Source = source;
        MethodInfo = methodInfo;
        Target = target;
    }
    public object Source { get; set; }
    public MethodInfo MethodInfo { get; set; }
    public object Target { get; set; }
    
    //执行订阅响应
    public void Invoke(object sender, object data)
    {
        if (sender == null || sender == Source) return;
        if (MethodInfo.IsStatic)
        {
            MethodInfo.Invoke(null, MethodInfo.GetParameters().Length == 1 ? new[] { sender } : new[] { sender, data });
            return;
        }
        MethodInfo?.Invoke(Target, MethodInfo.GetParameters().Length == 2 ? new[] { sender, data } : new[] { sender });
    }
}

最后,别忘了使用字典把订阅者存下来

public static class MessageCenter
{
    private static Dictionary<string, List<Subscription>> subs = new Dictionary<string, List<Subscription>>();
    
    //.....内部代码
    
}

使用也是非常的方便,Bar 向消息中心订阅通道,Foo 向消息中心推送消息,完成后会打印出从 Foo 传到 Bar 的消息

public class Bar
{
    public void Start()
    {
        MessageCenter.SubScribe<Foo,string>(this, "测试通道", Handle);
    }
    
    private void Handle(Foo sender,string data)
    {
        Console.WriteLine(data);
    }
}

public class Foo
{
    public void Start()
    {
        MessageCenter.Send(this, "测试通道", "这是一条测试信息");
    }
}
Foo foo = new Foo();
Bar bar = new Bar();
//注意,这里要先注册订阅
bar.Start();
foo.Start();
其他阅读

安卓开发 | 实现输入框自动全选内容

在安卓开发中,当用户手动选中输入框时。输入框内部的内容全部选中是一个比较提升用户体验的功能,主要用在一些复制的场景中。

查看原文

Winsaa 解锁 Windows 时间管理新姿势

了解自我时间分配,从记录每一秒开始。Winsaa 是轻码科技推出的一款 Windows 屏幕应用使用分析软件,它自动精准追踪每个应用的使用时长,并生成可视化报告,帮助你提升工作与学习效率。

查看原文

WPF 入门系列

WPF 全称为 Windows Presentation Foundation,是微软为 .Net 平台打造的一个 Windows 桌面应用程序的UI开发框架。使用 XAML 来描述界面代码,提供了丰富的图形、动画、数据绑定和样式功能,允许设计和开发分离,支持创建高度交互、视觉效果丰富的用户界面。本系列将会带你从项目入手,学会 WPF 的使用。

查看原文

Open Graph优化SEO

Open Graph(OG)协议作为社交分享优化的核心技术,不仅决定了内容在社交媒体平台的展示效果,还间接影响搜索引擎优化(SEO)的表现。本文将从作用解析、核心标签配置到动态生成策略,全面介绍 Open Graph 的应用。

查看原文

JavaScript构建一个Markdown解析器

Markdown是一种轻量级标记语言,以简单易读的语法和可生成丰富多彩的内容,受到开发者们的青睐。无论是文档编写,还是博客传记都广泛使用到Markdown。本文介绍试用JavaScript来构建一个Markdown解析器,解锁Markdown的强大之处。

查看原文