From ab2e319b2358611cf76651285611d0fc3f18ab01 Mon Sep 17 00:00:00 2001 From: "Daniel C. Weber" Date: Tue, 2 Oct 2018 16:30:22 +0200 Subject: [PATCH 1/2] Remove unused allocation/assignment. --- Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs b/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs index 24944fad1b..d38dbed9fc 100644 --- a/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs +++ b/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs @@ -92,8 +92,7 @@ private void Add(Delegate handler, IDisposable disposable) { lock (_subscriptions) { - var l = new Stack(); - if (!_subscriptions.TryGetValue(handler, out l)) + if (!_subscriptions.TryGetValue(handler, out var l)) { _subscriptions[handler] = l = new Stack(); } @@ -118,8 +117,7 @@ protected void Remove(Delegate handler) lock (_subscriptions) { - var l = new Stack(); - if (_subscriptions.TryGetValue(handler, out l)) + if (_subscriptions.TryGetValue(handler, out var l)) { d = l.Pop(); From 33c85e06e2318c34a78ac24fc9e27620a9e591e6 Mon Sep 17 00:00:00 2001 From: "Daniel C. Weber" Date: Tue, 2 Oct 2018 17:08:43 +0200 Subject: [PATCH 2/2] Use a dedicated implementation of IObserver instead of passing three delegates to Subscribe. --- .../System.Reactive/EventPatternSourceBase.cs | 95 ++++++++++++------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs b/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs index d38dbed9fc..83c469e715 100644 --- a/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs +++ b/Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs @@ -15,6 +15,66 @@ namespace System.Reactive /// The type of the event data generated by the event. public abstract class EventPatternSourceBase { + private sealed class Observer : ObserverBase>, ISafeObserver> + { + private bool _isDone; + private bool _isAdded; + private readonly Delegate _handler; + private readonly object _gate = new object(); + private readonly Action _invoke; + private readonly EventPatternSourceBase _sourceBase; + + public Observer(EventPatternSourceBase sourceBase, Delegate handler, Action invoke) + { + _handler = handler; + _invoke = invoke; + _sourceBase = sourceBase; + } + + protected override void OnNextCore(EventPattern value) + { + _sourceBase._invokeHandler(_invoke, value); + } + + protected override void OnErrorCore(Exception error) + { + Remove(); + error.Throw(); + } + + protected override void OnCompletedCore() + { + Remove(); + } + + private void Remove() + { + lock (_gate) + { + if (_isAdded) + { + _sourceBase.Remove(_handler); + } + else + { + _isDone = true; + } + } + } + + public void SetResource(IDisposable resource) + { + lock (_gate) + { + if (!_isDone) + { + _sourceBase.Add(_handler, resource); + _isAdded = true; + } + } + } + } + private readonly IObservable> _source; private readonly Dictionary> _subscriptions; private readonly Action, /*object,*/ EventPattern> _invokeHandler; @@ -50,42 +110,11 @@ protected void Add(Delegate handler, Action invoke) throw new ArgumentNullException(nameof(invoke)); } - var gate = new object(); - var isAdded = false; - var isDone = false; - - var remove = new Action(() => - { - lock (gate) - { - if (isAdded) - { - Remove(handler); - } - else - { - isDone = true; - } - } - }); - + var observer = new Observer(this, handler, invoke); // // [OK] Use of unsafe Subscribe: non-pretentious wrapper of an observable in an event; exceptions can occur during +=. // - var d = _source.Subscribe/*Unsafe*/( - x => _invokeHandler(invoke, /*this,*/ x), - ex => { remove(); ex.Throw(); }, - remove - ); - - lock (gate) - { - if (!isDone) - { - Add(handler, d); - isAdded = true; - } - } + observer.SetResource(_source.Subscribe(observer)); } private void Add(Delegate handler, IDisposable disposable)