Обработчик событий против объекта Rx

#c# #.net-core #system.reactive

#c# #.net-ядро #система.реактивная

Вопрос:

Я использую System.Reactive и не знаю, что выбрать: обработчики событий или Темы. В чем разница между ними?

 var client = WebSocketClient.Create(uri);  // Subject client.OnConnected  .Subscribe(_ =gt; { Log.Information($"Socket {client.Id} connected"); })  .DisposeWith(disposable);  // EventHandler Observable  .FromEventPattern(h =gt; client.Connected  = h, h =gt; client.Connected -= h)  .Select(_ =gt; Unit.Default)  .Subscribe(_ =gt; { Log.Information($"Socket {client.Id} connected"); })  .DisposeWith(disposable);  
 public class WebSocketClient : IWebSocketClient {  // Subject  private readonly ISubjectlt;Unitgt; _connectedSubject = new Subjectlt;Unitgt;();   public IObservablelt;Unitgt; OnConnected =gt; _connectedSubject.AsObservable();   // EventHandler  private EventHandler? _connected;   public event EventHandler Connected  {  add =gt; _connected  = value;  remove =gt; _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 EventHandlerlt;Unitgt; _bang;    public IObservablelt;Unitgt; Bangs =gt;  Observable  .FromEventPatternlt;Unitgt;(h =gt; _bang  = h, h =gt; _bang -= h)  .Select(x =gt; x.EventArgs);    private Subjectlt;Unitgt; _boom = new Subjectlt;Unitgt;();   public IObservablelt;Unitgt; Booms =gt;  _boom.AsObservable();    public void OnExplode()  {  _bang?.Invoke(this, Unit.Default);  _boom.OnNext(Unit.Default);  } }  

Теперь я могу его выполнить:

 var foo = new Foo();   foo.Bangs.Subscribe(_ =gt; Console.WriteLine("Bang!"));  foo.Booms.Subscribe(_ =gt; Console.WriteLine("Boom!"));   foo.OnExplode();  

Результат, который я получаю на консоли, таков:

 Bang! Boom!  

Код хорошо справляется с этой задачей.

Теперь проблема с обоими подходами заключается в гнусном программисте этого Foo класса. Они могли бы добавить этот метод:

 public void Nefarious() {  _boom.OnCompleted();  _bang = null; }  

Это эффективно убивает код.

Теперь я мог бы запустить это:

 var foo = new Foo();  foo.Bangs.Subscribe(_ =gt; Console.WriteLine("Bang!")); foo.Booms.Subscribe(_ =gt; Console.WriteLine("Boom!"));  foo.OnExplode(); foo.Nefarious(); foo.OnExplode();  

И я все равно увижу результат только один раз.

И то, и другое может быть повреждено.

В целом, однако, я нахожу, что немногие люди назначают своих делегатов на мероприятие null .

Гораздо более вероятно, что тема будет закрыта или произойдет ошибка, что приведет к остановке работы формы кода.