/// <summary> /// Creates an observable list from a specified cancellable asynchronous Subscribe method. The CancellationToken passed to the asynchronous Subscribe method is tied to the returned disposable subscription, allowing best-effort cancellation. /// </summary> /// <typeparam name="T">The type of the elements contained in the observable list</typeparam> /// <param name="subscribe"> Implementation of the resulting observable list's Subscribe method. </param> /// <returns>The observable list with the specified implementation for the Subscribe method.</returns> public static IObservable <IChangeSet <T> > Create <T>(Func <ISourceList <T>, CancellationToken, Task <Action> > subscribe) { if (subscribe == null) { throw new ArgumentNullException(nameof(subscribe)); } return(Observable.Create <IChangeSet <T> >(async(observer, ct) => { var list = new SourceList <T>(); Action disposeAction = null; try { disposeAction = await subscribe(list, ct); } catch (Exception e) { observer.OnError(e); } return new CompositeDisposable(list.Connect().SubscribeSafe(observer), list, Disposable.Create(() => { observer.OnCompleted(); disposeAction?.Invoke(); })); })); }
/// <summary> /// Creates an observable list from a specified Subscribe method implementation. /// </summary> /// <typeparam name="T">The type of the elements contained in the observable list</typeparam> /// <param name="subscribe"> Implementation of the resulting observable list's Subscribe method. </param> /// <returns>The observable list with the specified implementation for the Subscribe method.</returns> public static IObservable <IChangeSet <T> > Create <T>(Func <ISourceList <T>, IDisposable> subscribe) { if (subscribe == null) { throw new ArgumentNullException(nameof(subscribe)); } return(Observable.Create <IChangeSet <T> >(observer => { var list = new SourceList <T>(); IDisposable disposeAction = null; try { disposeAction = subscribe(list); } catch (Exception e) { observer.OnError(e); } return new CompositeDisposable(list.Connect().SubscribeSafe(observer), list, Disposable.Create(() => { observer.OnCompleted(); disposeAction?.Dispose(); })); })); }
/// <summary> /// Creates an observable list from a specified cancellable asynchronous Subscribe method. The CancellationToken passed to the asynchronous Subscribe method is tied to the returned disposable subscription, allowing best-effort cancellation. /// </summary> /// <typeparam name="T">The type of the elements contained in the observable list.</typeparam> /// <param name="subscribe"> Implementation of the resulting observable list's Subscribe method. </param> /// <returns>The observable list with the specified implementation for the Subscribe method.</returns> public static IObservable <IChangeSet <T> > Create <T>(Func <ISourceList <T>, CancellationToken, Task <IDisposable> > subscribe) { if (subscribe is null) { throw new ArgumentNullException(nameof(subscribe)); } return(Observable.Create <IChangeSet <T> >( async(observer, ct) => { var list = new SourceList <T>(); IDisposable?disposeAction = null; SingleAssignmentDisposable actionDisposable = new(); try { disposeAction = await subscribe(list, ct).ConfigureAwait(false); } catch (Exception e) { observer.OnError(e); } return new CompositeDisposable( list.Connect().SubscribeSafe(observer), list, actionDisposable, Disposable.Create( () => { observer.OnCompleted(); disposeAction?.Dispose(); })); })); }
/// <summary> /// Creates an observable list from a specified asynchronous Subscribe method. /// </summary> /// <typeparam name="T">The type of the elements contained in the observable list</typeparam> /// <param name="subscribe"> Implementation of the resulting observable list's Subscribe method. </param> /// <returns>The observable list with the specified implementation for the Subscribe method.</returns> public static IObservable <IChangeSet <T> > Create <T>(Func <ISourceList <T>, Task> subscribe) { if (subscribe == null) { throw new ArgumentNullException(nameof(subscribe)); } return(Observable.Create <IChangeSet <T> >(async observer => { var list = new SourceList <T>(); try { await subscribe(list).ConfigureAwait(false); } catch (Exception e) { observer.OnError(e); } return new CompositeDisposable(list.Connect().SubscribeSafe(observer), list, Disposable.Create(observer.OnCompleted)); })); }
public static IObservable <IChangeSet <TObject> > DelayRemove <TObject>(this IObservable <IChangeSet <TObject> > source, TimeSpan delayPeriod, Action <TObject> onDefer) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (onDefer == null) { throw new ArgumentNullException(nameof(onDefer)); } return(Observable.Create <IChangeSet <TObject> >(observer => { var removed = new [] { ListChangeReason.Remove, ListChangeReason.Clear, ListChangeReason.RemoveRange }; var localList = new SourceList <TObject>(); var locker = new object(); var shared = source.Synchronize(locker).Publish(); var notRemoved = shared.WhereReasonsAreNot(removed) .Subscribe(changes => { localList.Edit(innerList => { changes.ForEach(change => { switch (change.Reason) { case ListChangeReason.Add: innerList.Add(change.Item.Current); break; case ListChangeReason.AddRange: change.Range.ForEach(innerList.Add); break; case ListChangeReason.Replace: innerList.Replace(change.Item.Previous.Value, change.Item.Current); break; } }); }); }); //when removed,invoke call back var removes = shared.WhereReasonsAre(removed) .ForEachItemChange(change => onDefer(change.Current)) .Delay(delayPeriod) .Synchronize(locker) .Subscribe(changes => { //flatten removes into a single enumerable var toRemove = changes.SelectMany(change => { return change.Type == ChangeType.Item ? new[] { change.Item.Current } : change.Range.Select(t => t); }).ToArray(); //remove in one hit localList.RemoveMany(toRemove); }); var subscriber = localList.Connect().SubscribeSafe(observer); return new CompositeDisposable(subscriber, removes, notRemoved, shared.Connect()); })); }