public void CompositeDisposable_Remove() { var disp1 = false; var disp2 = false; var d1 = Disposable.Create(() => { disp1 = true; }); var d2 = Disposable.Create(() => { disp2 = true; }); var g = new CompositeDisposable(d1, d2); Assert.Equal(2, g.Count); Assert.True(g.Contains(d1)); Assert.True(g.Contains(d2)); Assert.True(g.Remove(d1)); Assert.Equal(1, g.Count); Assert.False(g.Contains(d1)); Assert.True(g.Contains(d2)); Assert.True(disp1); Assert.True(g.Remove(d2)); Assert.False(g.Contains(d1)); Assert.False(g.Contains(d2)); Assert.True(disp2); var disp3 = false; var d3 = Disposable.Create(() => { disp3 = true; }); Assert.False(g.Remove(d3)); Assert.False(disp3); }
private void OnRemoved(CollectionRemoveEvent <Card> removed) { IDisposable healthSubscription = healthSubscriptions[removed.Index]; healthSubscription.Dispose(); healthSubscriptions.RemoveAt(removed.Index); IDisposable droppedSubscription = droppedSubscriptions[removed.Index]; droppedSubscription.Dispose(); droppedSubscriptions.RemoveAt(removed.Index); cardSubscriptions.Remove(healthSubscription); cardSubscriptions.Remove(droppedSubscription); }
public void CompositeDisposable_RemoveOptimizationBehavior() { var g = new CompositeDisposable(); var m = new Dictionary <int, IDisposable>(); var r = new List <int>(); var N = 100; for (var i = 0; i < N; i++) { var j = i; var d = Disposable.Create(() => r.Add(j)); m[j] = d; g.Add(d); } var d1 = Enumerable.Range(0, N).Where(i => i % 2 == 0).ToArray(); foreach (var i in d1) { g.Remove(m[i]); } Assert.True(r.SequenceEqual(d1)); var d2 = Enumerable.Range(0, N).Where(i => i % 3 == 0).ToArray(); foreach (var i in d2) { g.Remove(m[i]); } Assert.True(r.SequenceEqual(d1.Concat(d2.Where(x => !d1.Any(y => x == y))))); var d3 = Enumerable.Range(0, N).Where(i => i % 5 == 0).ToArray(); foreach (var i in d3) { g.Remove(m[i]); } Assert.True(r.SequenceEqual(d1.Concat(d2.Where(x => !d1.Any(y => x == y))).Concat(d3.Where(x => !d1.Any(y => x == y) && !d2.Any(y => x == y))))); g.Dispose(); var z = r.Except(d1.Union(d2).Union(d3)).ToArray(); Assert.True(z.SequenceEqual(Enumerable.Range(0, N).Where(i => !(i % 2 == 0 || i % 3 == 0 || i % 5 == 0)))); }
/// <summary> /// Stop Alerts /// </summary> public void Stop() { if (_Cancel != null) { _Disposables.Remove(_Cancel); } _Cancel?.Cancel(); _Cancel?.Dispose(); if (_timer != null) { _Disposables.Remove(_timer); } _timer?.Dispose(); }
private IDisposable SubscribeInternal(IObserver <T> observer, int count) { Contract.Requires(observer != null); Contract.Requires(count >= subscribeUnlimited); Contract.Ensures(Contract.Result <IDisposable>() != null); EnsureNotDisposed(); var subscription = new SingleAssignmentDisposable(); IDisposable wrapper = null; wrapper = Disposable.Create(() => { subscription.Dispose(); disposables.Remove(wrapper); }); disposables.Add(wrapper); subscription.Disposable = cursor.Subscribe(observer, currentIndex, count); // User code is being called, so it's possible that the branch will be disposed synchronously. if (!disposed) { Contract.Assume(currentIndex > cursor.latestIndex || cursor.elements.Count >= cursor.latestIndex - currentIndex); Contract.Assume(!cursor.stopped || currentIndex <= cursor.latestIndex + 1); Contract.Assume(currentIndex >= cursor.firstElementIndex); } return(wrapper); }
public void CompositeDisposableTests_DisposeTest() { bool disposed = false; using (var compositeDisposable = new CompositeDisposable()) { var item = new SIDisposable(); compositeDisposable.Add(item); Assert.AreEqual(1, compositeDisposable.Count); compositeDisposable.Remove(item); Assert.AreEqual(0, compositeDisposable.Count); compositeDisposable.Add(item); Assert.AreEqual(1, compositeDisposable.Count); Assert.AreEqual(item, compositeDisposable[0]); compositeDisposable[0] = new SIDisposable(); Assert.AreNotEqual(item, compositeDisposable[0]); compositeDisposable.Clear(); Assert.AreEqual(0, compositeDisposable.Count); compositeDisposable.Add(item); Assert.IsTrue(compositeDisposable.Contains(item)); item.DisposeAction = () => disposed = true; } Assert.IsTrue(disposed); }
private IDisposable subscribe(Destination destination, Action <Message> callback, string messageType) { IDisposable subscription = null; string[] selectors = new[] { messageType != null ? "JMSType = '" + messageType + "'" : null, m_JailedTag != null ? JailedSelector : null }.Where(x => x != null).ToArray(); MessageConsumer consumer = selectors.Length == 0 ? m_Session.createConsumer(destination) : m_Session.createConsumer(destination, string.Join(" AND ", selectors)); consumer.setMessageListener(new GenericMessageListener(callback)); subscription = Disposable.Create(() => { lock (this) { consumer.close(); // ReSharper disable AccessToModifiedClosure m_Subscriptions.Remove(subscription); // ReSharper restore AccessToModifiedClosure if (m_Subscriptions.Count == 0) { m_Session.close(); m_Session = null; } } }); m_Subscriptions.Add(subscription); return(subscription); }
[ContractVerification(false)] // Static checker is timing out public IDisposable Connect() { // Ensurances about field mutability cannot be made because user code is invoked. Contract.Ensures(latestIndex >= -1); // Helps the static checker when analyzing the nested branch class, since invariants are ignored. EnsureNotDisposed(); if (source == null) { throw new InvalidOperationException(); } if (!connected) { // Set the variable first in case of reentry. connected = true; var subscription = source.Subscribe(OnNext, OnError, OnCompleted); sourceSubscription = Disposable.Create(() => { subscription.Dispose(); disposables.Remove(sourceSubscription); connected = false; Reset(); }); disposables.Add(sourceSubscription); } return(sourceSubscription); }
/// <summary> /// Merges an observable sequence of observable sequences into an observable sequence. /// </summary> public static IObservable <TSource> Merge <TSource>(this IObservable <IObservable <TSource> > source) { if (source == null) { throw new ArgumentNullException("source"); } return(new AnonymousObservable <TSource>(observer => { var gate = new object(); var isStopped = false; var group = new CompositeDisposable(); var outerSubscription = new MutableDisposable(); group.Add(outerSubscription); outerSubscription.Disposable = source.Subscribe( innerSource => { var innerSubscription = new MutableDisposable(); group.Add(innerSubscription); innerSubscription.Disposable = innerSource.Subscribe( x => { lock (gate) observer.OnNext(x); }, exception => { lock (gate) observer.OnError(exception); }, () => { group.Remove(innerSubscription); // modification MUST occur before subsequent check if (isStopped && group.Count == 1) // isStopped must be checked before group Count to ensure outer is not creating more groups { lock (gate) observer.OnCompleted(); } }); }, exception => { lock (gate) observer.OnError(exception); }, () => { isStopped = true; // modification MUST occur before subsequent check if (group.Count == 1) { lock (gate) observer.OnCompleted(); } }); return group; })); }
private IDisposable subscribe(IDestination destination, Action <IMessage> callback, string messageType) { IDisposable subscription = null; var selectors = new List <string>(); selectors.Add(messageType != null ? "JMSType = '" + messageType + "'" : null); selectors.Add(m_JailedTag != null ? m_JailedSelector : null); selectors.AddRange(m_CustomSelectors.Select(param => param.Key + " = '" + param.Value + "'")); var selectorsArray = selectors.Where(x => x != null).ToArray(); IMessageConsumer consumer = selectorsArray.Length == 0 ? m_Session.CreateConsumer(destination) : m_Session.CreateConsumer(destination, string.Join(" AND ", selectorsArray)); consumer.Message += (sender, args) => callback(args.Message); subscription = Disposable.Create(() => { lock (this) { consumer.Close(); // ReSharper disable AccessToModifiedClosure m_Subscriptions.Remove(subscription); // ReSharper restore AccessToModifiedClosure if (m_Subscriptions.Count == 0) { m_Session.Close(); m_Session = null; } } }); m_Subscriptions.Add(subscription); return(subscription); }
private void CreateNewServiceInstance(IService service, Socket socket) { var instance = new ServiceInstance <TService>(NodeId, service, socket); instance.StartAsync(ServiceName) .ContinueWith(startTask => { if (startTask.Status == TaskStatus.RanToCompletion) { var lazyDisposable = new SingleAssignmentDisposable(); var d = startTask.Result.Subscribe( _ => { }, ex => lazyDisposable.Dispose(), lazyDisposable.Dispose); lock (_instanceDisposables) { _instanceDisposables.Add(d); } lazyDisposable.Disposable = Disposable.Create(() => { d.Dispose(); lock (_instanceDisposables) { _instanceDisposables.Remove(d); } }); } else if (startTask.Status == TaskStatus.Faulted) { _logger.Error("ServiceServer: StartAsync Error", startTask.Exception.InnerException); } }); }
public static IObservable <TSource> SkipLast <TSource> ( this IObservable <TSource> source, TimeSpan duration, IScheduler scheduler) { if (source == null) { throw new ArgumentNullException("source"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } duration = Scheduler.Normalize(duration); return(new ColdObservableEach <TSource> (sub => { // ---- DateTimeOffset start = scheduler.Now; var q = new CompositeDisposable(); return source.Subscribe(Observer.Create <TSource> (s => { IDisposable task = null; task = scheduler.Schedule(duration, () => { sub.OnNext(s); q.Remove(task); }); q.Add(task); }, ex => { q.Dispose(); // cancel all existing tasks. sub.OnError(ex); }, () => { q.Dispose(); // cancel all existing tasks. sub.OnCompleted(); })); // ---- }, scheduler)); }
public static IObservable <IObservable <TSource> > Window <TSource> ( this IObservable <TSource> source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) { if (source == null) { throw new ArgumentNullException("source"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } if (timeSpan < TimeSpan.Zero) { throw new ArgumentOutOfRangeException("timeSpan"); } if (timeShift < TimeSpan.Zero) { throw new ArgumentOutOfRangeException("timeShift"); } return(new ColdObservableEach <IObservable <TSource> > (sub => { // ---- var subjects = new List <SubjectTimeShiftContext <TSource> > (); DateTimeOffset nextStart = scheduler.Now; var dis = new CompositeDisposable(); dis.Add(source.Subscribe(Observer.Create <TSource> (v => { if (nextStart <= scheduler.Now) { var lc = new SubjectTimeShiftContext <TSource> (nextStart, new ReplaySubject <TSource> ()); subjects.Add(lc); sub.OnNext(lc.Subject); nextStart += timeShift; var ddis = new SingleAssignmentDisposable(); ddis.Disposable = scheduler.Schedule(timeSpan, () => { lc.Subject.OnCompleted(); subjects.Remove(lc); dis.Remove(ddis); }); } for (int x = 0; x < subjects.Count; x++) { // This check makes sense when the event was published *at the same time* the subject ends its life time by timeSpan. if (scheduler.Now - subjects [x].Start < timeSpan) { subjects [x].Subject.OnNext(v); } } }, ex => sub.OnError(ex), () => { foreach (var sc in subjects) { sc.Subject.OnCompleted(); } sub.OnCompleted(); }))); return dis; // ---- }, DefaultColdScheduler)); }
public void OnNavigatedTo(NavigationContext navigationContext) { if ((null != navigationContext) && !navigationContext.Parameters["view"].Equals(_AlertSource)) { try { _AlertSource = (string)navigationContext.Parameters["view"]; Models.AlertManager Alert = _Container.Resolve <Models.AlertManager>(); // Replace Live list if (null != Lives) { _Disposables.Remove(Lives); } Lives?.Dispose(); Lives = Alert.GetLiveList(_AlertSource).ToReadOnlyReactiveCollection().AddTo(_Disposables); // View filter CollectionViewSource.GetDefaultView(Lives).Filter = x => { if (string.IsNullOrWhiteSpace(FavoriteQuery.Value)) { return(true); } // sanitize //string escaped = System.Text.RegularExpressions.Regex.Escape(FavoriteQuery.Value); //return System.Text.RegularExpressions.Regex.IsMatch(x.Title, $"({escaped})+"); return(0 <= (x as Models.LiveItem)?.Descriptors[SelectedFavoriteQueryTarget.Value.Value].IndexOf(FavoriteQuery.Value)); }; // Generate columns List <Models.LiveItemColumn> columns = new List <Models.LiveItemColumn>(); Models.LiveDescriptor[] descs = Alert.GetQueryTargets(_AlertSource).Keys.ToArray(); for (int i = 0; i < descs.Length; i++) { columns.Add(new Models.LiveItemColumn(descs[i].Label, $"Descriptors[{i}]")); } columns.Add(new Models.LiveItemColumn("Start Date", nameof(Models.LiveItem.StartDate))); columns.Add(new Models.LiveItemColumn("URL", nameof(Models.LiveItem.Url))); LiveColumns = columns.ToArray(); // Notify LiveList PropertyChanged to View RaisePropertyChanged(nameof(Lives)); RaisePropertyChanged(nameof(LiveColumns)); // Replace query type list FavoriteQueryTargets = Alert.GetQueryTargets(_AlertSource); RaisePropertyChanged(nameof(FavoriteQueryTargets)); SelectedFavoriteQueryTarget.Value = FavoriteQueryTargets.First(); // Refresh favorite CollectionViewSource.GetDefaultView(Favorites).Refresh(); } catch (Exception ex) { _logger.Error(ex); } } }
public Task <View <NodeV1> > GetNodesView(string labelSelector = null) { var view = new View <NodeV1>(); var subscription = _client .NodesV1() .WatchAll(labelSelector) .ObserveOn(Scheduler) .Subscribe(view); _subscriptions.Add(subscription); view.AddDisposable(Disposable.Create(() => { subscription.Dispose(); _subscriptions.Remove(subscription); })); return(Task.FromResult(view)); }
/// <summary> /// Removes a disposable previously added with <see cref="AddDisposable"/> /// </summary> /// <param name="a_disposable">Disposable to remove</param> /// <param name="a_dispose">Should we dispose of the object automatically while removing it?</param> protected void RemoveDisposable(IDisposable a_disposable, bool a_dispose = false) { if (m_disposables == null) { return; } if (m_disposables.Remove(a_disposable) && a_dispose) { a_disposable.Dispose(); } }
/// <summary> /// Adds a reaction that depends on this view-model entering a specified <see cref="ViewModelState"/>. /// </summary> /// <param name="state"></param> /// <param name="action"></param> /// <returns></returns> public IDisposable AddTrigger(ViewModelState state, Action action) { var subscription = _state .Where(s => s == state) .OnBackground() .Subscribe( _ => action.VerifyThread(this.Dispatcher, false), error => /*Logs.UseLogger(l => l.ReportError("Observing state for trigger.", error))*/ { }); _subscriptions.Add(subscription); return(Disposable.Create(() => _subscriptions.Remove(subscription))); }
void IViewModel.Detach() { EnsureNotDisposed(); Detaching(); element = null; if (attachmentDisposable != null) { disposables.Remove(attachmentDisposable); attachmentDisposable = null; } }
public void StopUI(IUIController controller) { try { if (!controller.IsStopped) { controller.Stop(); } disposables.Remove(controller); } catch (Exception ex) { log.Error("Failed to dispose UI. {0}", ex); } }
/// <summary> /// 清除 eventType 的订阅, 如果 subject 非空, 则只清除 subject 的订阅 /// </summary> /// <param name="eventType"> 事件的具体类型 </param> /// <param name="subject"> 指定的订阅者 </param> /// <typeparam name="TEventData"> 事件数据的类型 </typeparam> /// <returns> 清除的结果 </returns> public bool Dispose <TEventData>(int eventType, Subject <TEventData> subject = null) { if (_eventDictionary.Count == 0) { return(false); } if (subject == null) { return(_eventDictionary.Remove(eventType)); } CompositeDisposable disposableList = GetDisposableList(eventType, false); return(disposableList != null && disposableList.Remove(subject)); }
static IDisposable InvokeRec1 <TState>(IScheduler scheduler, Pair <TState, Action <TState, Action <TState> > > pair) { var group = new CompositeDisposable(1); var gate = new object(); var state = pair.First; var action = pair.Second; Action <TState> recursiveAction = null; recursiveAction = state1 => action(state1, state2 => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(state2, (scheduler1, state3) => { lock (gate) { if (isAdded) { group.Remove(d); } else { isDone = true; } } recursiveAction(state3); return(Disposable.Empty); }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); recursiveAction(state); return(group); }
public ObservableCursorBranch(ObservableCursor <T> cursor, int currentIndex, CompositeDisposable parentDisposables) { Contract.Requires(cursor != null); Contract.Requires(cursor.branches != null); Contract.Requires(cursor.elements != null); Contract.Requires(cursor.latestIndex >= -1); Contract.Requires(currentIndex >= 0); Contract.Requires(currentIndex >= cursor.firstElementIndex); Contract.Requires(currentIndex > cursor.latestIndex || cursor.elements.Count >= cursor.latestIndex - currentIndex); Contract.Requires(!cursor.stopped || currentIndex <= cursor.latestIndex + 1); Contract.Requires(parentDisposables != null); Contract.Ensures(this.cursor == cursor); Contract.Ensures(this.currentIndex == currentIndex); Contract.Ensures(!IsSynchronized); Contract.Ensures(IsForwardOnly == cursor.IsForwardOnly); Contract.Ensures(IsSequenceTerminated == cursor.IsSequenceTerminated); Contract.Ensures(LatestIndex == cursor.latestIndex); Contract.Ensures(CurrentIndex == currentIndex); Contract.Ensures(AtEndOfSequence == (cursor.IsSequenceTerminated && currentIndex == cursor.latestIndex + 1)); this.cursor = cursor; this.currentIndex = currentIndex; parentDisposables.Add(this); cursor.branches.Add(this); bool removed = false; var subscription = Disposable.Create(() => { if (!removed) { // Set this variable first in case of reentry. removed = true; parentDisposables.Remove(this); cursor.branches.Remove(this); } }); disposables.Add(subscription); Contract.Assert(currentIndex > cursor.latestIndex || cursor.elements.Count >= cursor.latestIndex - currentIndex); }
public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action <Action <DateTimeOffset> > action) { // InvokeRec3 var group = new CompositeDisposable(1); var gate = new object(); Action recursiveAction = null; recursiveAction = () => action(dt => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(dt, () => { lock (gate) { if (isAdded) { group.Remove(d); } else { isDone = true; } } recursiveAction(); }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); group.Add(scheduler.Schedule(dueTime, recursiveAction)); return(group); }
protected override void Main() { TraceDescription(Instructions.MulticastLab); int current = 0; IObservable <int> source = Observable .Interval(TimeSpan.FromSeconds(1)) .Select(_ => current++) .Multicast(() => new ReplaySubject <int>()) .RefCount(); using (var disposables = new CompositeDisposable()) { do { var key = WaitForKey(); switch (key.KeyChar) { case '+': case '=': var id = (char)('A' + disposables.Count); var subscription = source.Subscribe(ConsoleOutput(id.ToString())); disposables.Add(subscription); break; case '-': case '_': if (disposables.Count > 0) { disposables.Remove(disposables.Last()); } break; default: return; } }while (true); } }
/// <summary> /// Adds the trait instance <see cref="T"/> to this collection, returning the actual instance /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T Add <T>() where T : IViewModelTrait { IViewModelTrait oldBehaviour; if (_children.TryGetValue(typeof(T), out oldBehaviour)) { oldBehaviour.Dispose(); _composite.Remove(oldBehaviour); } var parameterOverride = new ParameterOverrides { { "target", _parent } }; var newBehaviour = _container.Resolve <T>(parameterOverride); _children[typeof(T)] = newBehaviour; newBehaviour.DisposeWith(this); return(newBehaviour); }
/// <summary> /// Adds the trait instance <see cref="T"/> to this collection, returning the actual instance /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T Add <T>() where T : IViewModelTrait { IViewModelTrait oldBehaviour; if (_children.TryGetValue(typeof(T), out oldBehaviour)) { oldBehaviour.Dispose(); _composite.Remove(oldBehaviour); } var newBehaviour = _resolver.ResolveWithParent <T>(_parent); if (newBehaviour != null) { _children[typeof(T)] = newBehaviour; newBehaviour.DisposeWith(this); } return(newBehaviour); }
public void CompositeDisposable_GetEnumerator_Disposed_Entries() { var d1 = new BooleanDisposable(); var d2 = new BooleanDisposable(); var d3 = new BooleanDisposable(); var composite = new CompositeDisposable(d1, d2, d3); composite.Remove(d2); var enumerator = composite.GetEnumerator(); Assert.True(enumerator.MoveNext()); Assert.Equal(d1, enumerator.Current); Assert.True(enumerator.MoveNext()); Assert.Equal(d3, enumerator.Current); Assert.False(enumerator.MoveNext()); }
public IDisposable Schedule <TState> (TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) #endif { var dis = new SingleAssignmentDisposable(); bool cancel = false; var th = thread_factory(() => { Thread.Sleep(Scheduler.Normalize(dueTime)); if (!cancel) { dis.Disposable = action(this, state); } }); th.Start(); // The thread is not aborted even if it's at work (ThreadAbortException is not caught inside the action). var ret = Disposable.Create(() => { cancel = true; dis.Dispose(); disposables.Remove(dis); }); disposables.Add(ret); return(ret); }
void InitChannelControl(DeviceChannelControl channControl, ChannelDescription chan, SourcesArgs args, string proftoken = null) { //try to remove and clear all needed data if (channControl.Content is IDisposable) { var disp = channControl.Content as IDisposable; //try to remove content from disposables collection if (disposables.Contains(disp)) { disposables.Remove(disp); } //dispose existing control disp.Dispose(); } //Begin load channels section disposables.Add(SourceView.Load(chan, args.capabilities, args.nvtSession, args.odmSession, proftoken) .ObserveOnCurrentDispatcher() .Subscribe(sourceArgs => { if (sourceArgs.selectedProfile != null) { channControl.Title = sourceArgs.channelDescr.videoSource.token + ": " + sourceArgs.selectedProfile.name; } else { channControl.Title = sourceArgs.channelDescr.videoSource.token; } SourceView sourceView = new SourceView(container); disposables.Add(sourceView); sourceView.Init(sourceArgs); channControl.Content = sourceView; }, err => { ErrorView errorView = new ErrorView(err); disposables.Add(errorView); channControl.Content = errorView; } )); }
void InitEngineControl(DeviceEngineControl engineControl, AnalyticsEngine engine, AnalyticsArgs args, string ctrltoken = null) { //try to remove and clear all needed data if (engineControl.Content is IDisposable) { var disp = engineControl.Content as IDisposable; //try to remove content from disposables collection if (disposables.Contains(disp)) { disposables.Remove(disp); } //dispose existing control disp.Dispose(); } //Begin load channels section disposables.Add(EnginesView.Load(engine, args.capabilities, args.nvtSession, args.odmSession, ctrltoken) .ObserveOnCurrentDispatcher() .Subscribe(ctrlArgs => { if (ctrlArgs.selectedEngineControl != null) { engineControl.Title = ctrlArgs.engine.name + ": " + ctrlArgs.selectedEngineControl.name; } else { engineControl.Title = ctrlArgs.engine.name; } EnginesView enginesView = new EnginesView(container); disposables.Add(enginesView); enginesView.Init(ctrlArgs); engineControl.Content = enginesView; }, err => { ErrorView errorView = new ErrorView(err); disposables.Add(errorView); engineControl.Content = errorView; } )); }
public static IDisposable Schedule(this IScheduler scheduler, Action<Action> action) { // InvokeRec1 var group = new CompositeDisposable(1); var gate = new object(); Action recursiveAction = null; recursiveAction = () => action(() => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(() => { lock (gate) { if (isAdded) group.Remove(d); else isDone = true; } recursiveAction(); }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); group.Add(scheduler.Schedule(recursiveAction)); return group; }
public void Remove() { var d = new CompositeDisposable (); d.Remove (Disposable.Empty); // no effect, no error. }