Skip to content

Commit 4d72bb1

Browse files
authored
Merge pull request #820 from danielcweber/ReviewEventPatternSourceBase
Review EventPatternSourceBase
2 parents 9a6e8b2 + 33c85e0 commit 4d72bb1

File tree

1 file changed

+64
-37
lines changed

1 file changed

+64
-37
lines changed

Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,66 @@ namespace System.Reactive
1515
/// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
1616
public abstract class EventPatternSourceBase<TSender, TEventArgs>
1717
{
18+
private sealed class Observer : ObserverBase<EventPattern<TSender, TEventArgs>>, ISafeObserver<EventPattern<TSender, TEventArgs>>
19+
{
20+
private bool _isDone;
21+
private bool _isAdded;
22+
private readonly Delegate _handler;
23+
private readonly object _gate = new object();
24+
private readonly Action<TSender, TEventArgs> _invoke;
25+
private readonly EventPatternSourceBase<TSender, TEventArgs> _sourceBase;
26+
27+
public Observer(EventPatternSourceBase<TSender, TEventArgs> sourceBase, Delegate handler, Action<TSender, TEventArgs> invoke)
28+
{
29+
_handler = handler;
30+
_invoke = invoke;
31+
_sourceBase = sourceBase;
32+
}
33+
34+
protected override void OnNextCore(EventPattern<TSender, TEventArgs> value)
35+
{
36+
_sourceBase._invokeHandler(_invoke, value);
37+
}
38+
39+
protected override void OnErrorCore(Exception error)
40+
{
41+
Remove();
42+
error.Throw();
43+
}
44+
45+
protected override void OnCompletedCore()
46+
{
47+
Remove();
48+
}
49+
50+
private void Remove()
51+
{
52+
lock (_gate)
53+
{
54+
if (_isAdded)
55+
{
56+
_sourceBase.Remove(_handler);
57+
}
58+
else
59+
{
60+
_isDone = true;
61+
}
62+
}
63+
}
64+
65+
public void SetResource(IDisposable resource)
66+
{
67+
lock (_gate)
68+
{
69+
if (!_isDone)
70+
{
71+
_sourceBase.Add(_handler, resource);
72+
_isAdded = true;
73+
}
74+
}
75+
}
76+
}
77+
1878
private readonly IObservable<EventPattern<TSender, TEventArgs>> _source;
1979
private readonly Dictionary<Delegate, Stack<IDisposable>> _subscriptions;
2080
private readonly Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> _invokeHandler;
@@ -50,50 +110,18 @@ protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)
50110
throw new ArgumentNullException(nameof(invoke));
51111
}
52112

53-
var gate = new object();
54-
var isAdded = false;
55-
var isDone = false;
56-
57-
var remove = new Action(() =>
58-
{
59-
lock (gate)
60-
{
61-
if (isAdded)
62-
{
63-
Remove(handler);
64-
}
65-
else
66-
{
67-
isDone = true;
68-
}
69-
}
70-
});
71-
113+
var observer = new Observer(this, handler, invoke);
72114
//
73115
// [OK] Use of unsafe Subscribe: non-pretentious wrapper of an observable in an event; exceptions can occur during +=.
74116
//
75-
var d = _source.Subscribe/*Unsafe*/(
76-
x => _invokeHandler(invoke, /*this,*/ x),
77-
ex => { remove(); ex.Throw(); },
78-
remove
79-
);
80-
81-
lock (gate)
82-
{
83-
if (!isDone)
84-
{
85-
Add(handler, d);
86-
isAdded = true;
87-
}
88-
}
117+
observer.SetResource(_source.Subscribe(observer));
89118
}
90119

91120
private void Add(Delegate handler, IDisposable disposable)
92121
{
93122
lock (_subscriptions)
94123
{
95-
var l = new Stack<IDisposable>();
96-
if (!_subscriptions.TryGetValue(handler, out l))
124+
if (!_subscriptions.TryGetValue(handler, out var l))
97125
{
98126
_subscriptions[handler] = l = new Stack<IDisposable>();
99127
}
@@ -118,8 +146,7 @@ protected void Remove(Delegate handler)
118146

119147
lock (_subscriptions)
120148
{
121-
var l = new Stack<IDisposable>();
122-
if (_subscriptions.TryGetValue(handler, out l))
149+
if (_subscriptions.TryGetValue(handler, out var l))
123150
{
124151
d = l.Pop();
125152

0 commit comments

Comments
 (0)