#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
.
Гораздо более вероятно, что тема будет закрыта или произойдет ошибка, что приведет к остановке работы формы кода.