EventHandler 与 Rx 主题

Posted

技术标签:

【中文标题】EventHandler 与 Rx 主题【英文标题】:EventHandler vs Rx Subject 【发布时间】:2022-01-12 08:08:44 【问题描述】:

我正在使用System.Reactive,但我不知道该选择哪一个:EventHandlers 或 Subjects。它们有什么区别?

var client = WebSocketClient.Create(uri);

// Subject
client.OnConnected
    .Subscribe(_ =>  Log.Information($"Socket client.Id connected"); )
    .DisposeWith(disposable);

// EventHandler
Observable
    .FromEventPattern(h => client.Connected += h, h => client.Connected -= h)
    .Select(_ => Unit.Default)
    .Subscribe(_ =>  Log.Information($"Socket client.Id connected"); )
    .DisposeWith(disposable);
public class WebSocketClient : IWebSocketClient

    // Subject
    private readonly ISubject<Unit> _connectedSubject = new Subject<Unit>();

    public IObservable<Unit> OnConnected => _connectedSubject.AsObservable();

    // EventHandler
    private EventHandler? _connected;

    public event EventHandler Connected
    
        add => _connected += value;
        remove => _connected -= value;
    

    // Logic
    async Task IWebSocketClient.ConnectAsync(CancellationToken cancellationToken)
    
        ...

        await _webSocket.ConnectAsync(_uri, cancellationToken).ConfigureAwait(false);

        _connected?.Invoke(this, EventArgs.Empty);

        _connectedSubject.OnNext();

        ...
    

    private void Dispose()
    
        _connectedSubject.OnCompleted();
    

【问题讨论】:

【参考方案1】:

这是一个示例代码,可以更好地说明使用主题而不是事件来创建可观察对象。

public class Foo

    private event EventHandler<Unit> _bang;
    
    public IObservable<Unit> Bangs =>
        Observable
            .FromEventPattern<Unit>(h => _bang += h, h => _bang -= h)
            .Select(x => x.EventArgs);
    
    private Subject<Unit> _boom = new Subject<Unit>();

    public IObservable<Unit> Booms =>
        _boom.AsObservable();
            
    public void OnExplode()
    
        _bang?.Invoke(this, Unit.Default);
        _boom.OnNext(Unit.Default);
    

现在我可以执行它了:

    var foo = new Foo();

    foo.Bangs.Subscribe(_ => Console.WriteLine("Bang!"));
    foo.Booms.Subscribe(_ => Console.WriteLine("Boom!"));

    foo.OnExplode();

我在控制台上得到的结果是这样的:

Bang!
Boom!

代码做得很好。

现在,这两种方法的关注点是Foo 类的邪恶编码器。他们可以添加这个方法:

public void Nefarious()

    _boom.OnCompleted();
    _bang = null;

这有效地杀死了代码。

现在我可以运行这个了:

var foo = new Foo();

foo.Bangs.Subscribe(_ => Console.WriteLine("Bang!"));
foo.Booms.Subscribe(_ => Console.WriteLine("Boom!"));

foo.OnExplode();
foo.Nefarious();
foo.OnExplode();

而且我仍然只会看到一次输出。

两者都可能损坏。

不过,总的来说,我发现很少有人将他们的事件代表设置为 null

主题很可能会结束或出错,从而停止代码表单的工作。

【讨论】:

以上是关于EventHandler 与 Rx 主题的主要内容,如果未能解决你的问题,请参考以下文章

event & EventHandler

Java中完美实现C#的EventHandler事件模式,代码优雅解耦合

Go语言事件请求处理程序(Event Handler)

IWebBrowser2 OnBeforeNavigate 事件 - EventHandler

[Vue-rx] Access Events from Vue.js Templates as RxJS Streams with domStreams

[C#]使用rx.net来帮助完成主动通知和订阅的功能