文章

【RxMvvmLight】0x0A 简易 MessageBus

MessageBus

在 MVVM 模式里,MessageBus 是一个兜底的东西,虽然我觉得这就是一个大号 goto,能不用就不用,但有些需求吧,不用它就得写好长的代码,所以这里还是有必要做一个的。

鉴于我已经有了丰富的 Dispose 操作符可以管理订阅,而且框架里到处都是强引用订阅,我这里就不考虑使用弱引用了,这样更一致。

订阅需要记得用 DisposeWithXXX 系列方法释放,不然会内存泄漏。

所以这个东西没啥好说的,直接看代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public sealed class MessageBus
{
    private MessageBus(){}

    public static readonly MessageBus Instance = new();

    public void Publish<TMessage>(TMessage message) => MessageBus<TMessage>.Instance.Publish(message);

    public IDisposable Subscribe<TMessage>(Action<TMessage> handler) => MessageBus<TMessage>.Instance.Subscribe(handler);
}

internal class MessageBus<TMessage>
{
    public static readonly MessageBus<TMessage> Instance = new();

    readonly Lock _gate = new();
    readonly List<Action<TMessage>> list = [];

    public void Publish(TMessage message)
    {
        List<Action<TMessage>> snapshot;
        lock (_gate)
            snapshot = [.. list];

        foreach (var sub in snapshot)
        {
            sub.Invoke(message);
        }
    }

    public IDisposable Subscribe(Action<TMessage> handler)
    {
        ArgumentNullException.ThrowIfNull(handler);

        lock (_gate)
            list.Add(handler);

        return Disposable.Create(() =>
        {
            lock (_gate)
                list.Remove(handler);
        });
    }
}

MessageBus 类型是单例类,这允许编写扩展方法。

这基本就是个带参数版本的 AsyncSignal,不过这里是纯同步的,因为我不想让消息通知变得太重,他应该就起一个传递信号的作用,如果有其他作用的话,建议用 AsyncSignal,虽然我没做带参数的版本hhh。

然后再学生命周期,加几个成套的扩展, 就齐活了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static class MessageBusExtensions
{
    extension(MessageBus self)
    {
        public IDisposable SubscribeOnce<TMessage>(Action<TMessage> handler, Predicate<TMessage>? predicate = null)
        {
            IDisposable? disposable = null;
            disposable = MessageBus.Instance.Subscribe<TMessage>(message =>
            {
                if (predicate is null || predicate(message))
                {
                    disposable?.Dispose();
                    handler(message);
                }
            });
            return disposable;
        }
    }

    extension(IDisposable self)
    {
        public IDisposable DisposeWithMessage<TMessage>(Predicate<TMessage>? predicate = null)
        {
            MessageBus.Instance.SubscribeOnce(_ =>
            {
                self.Dispose();
            }, predicate);
            return self;
        }
    }

    extension(IAsyncDisposable self)
    {
        public IAsyncDisposable DisposeWithMessage<TMessage>(Predicate<TMessage>? predicate = null)
        {
            MessageBus.Instance.SubscribeOnce(_ =>
            {
                self.DisposeAsync();
            }, predicate);
            return self;
        }
    }
}
本文由作者按照 CC BY 4.0 进行授权