【问题标题】:EventHandler vs Rx SubjectEventHandler 与 Rx 主题
【发布时间】: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();
    }
}

【问题讨论】:

    标签: c# .net-core system.reactive


    【解决方案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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      相关资源
      最近更新 更多