EventPatternSourceBase<TSender, TEventArgs>
using System.Collections.Generic;
namespace System.Reactive
{
public abstract class EventPatternSourceBase<TSender, TEventArgs>
{
private readonly IObservable<EventPattern<TSender, TEventArgs>> _source;
private readonly Dictionary<Delegate, Stack<IDisposable>> _subscriptions;
private readonly Action<Action<TSender, TEventArgs>, EventPattern<TSender, TEventArgs>> _invokeHandler;
protected EventPatternSourceBase(IObservable<EventPattern<TSender, TEventArgs>> source, Action<Action<TSender, TEventArgs>, EventPattern<TSender, TEventArgs>> invokeHandler)
{
if (source == null)
throw new ArgumentNullException("source");
if (invokeHandler == null)
throw new ArgumentNullException("invokeHandler");
_source = source;
_invokeHandler = invokeHandler;
_subscriptions = new Dictionary<Delegate, Stack<IDisposable>>();
}
protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)
{
if ((object)handler == null)
throw new ArgumentNullException("handler");
if (invoke == null)
throw new ArgumentNullException("invoke");
object gate = new object();
bool isAdded = false;
bool isDone = false;
Action remove = delegate {
lock (gate) {
if (isAdded)
Remove(handler);
else
isDone = true;
}
};
IDisposable disposable = ObservableExtensions.Subscribe<EventPattern<TSender, TEventArgs>>(_source, (Action<EventPattern<TSender, TEventArgs>>)delegate(EventPattern<TSender, TEventArgs> x) {
_invokeHandler(invoke, x);
}, (Action<Exception>)delegate(Exception ex) {
remove();
ex.Throw();
}, remove);
lock (gate) {
if (!isDone) {
Add(handler, disposable);
isAdded = true;
}
}
}
private void Add(Delegate handler, IDisposable disposable)
{
lock (_subscriptions) {
Stack<IDisposable> value = new Stack<IDisposable>();
if (!_subscriptions.TryGetValue(handler, out value))
value = (_subscriptions[handler] = new Stack<IDisposable>());
value.Push(disposable);
}
}
protected void Remove(Delegate handler)
{
if ((object)handler == null)
throw new ArgumentNullException("handler");
IDisposable disposable = null;
lock (_subscriptions) {
Stack<IDisposable> value = new Stack<IDisposable>();
if (_subscriptions.TryGetValue(handler, out value)) {
disposable = value.Pop();
if (value.Count == 0)
_subscriptions.Remove(handler);
}
}
disposable?.Dispose();
}
}
}