Beispiel #1
0
        private static IDisposable InvokeTaskWithDisposable <TState>(
            IScheduler scheduler,
            TState state,
            Func <CancellationToken, IScheduler, TState, Task <IDisposable> > taskBuilder,
            SchedulerSynchronizationContext schedulerContext)
        {
            var subscriptions = new SerialDisposable();

            var cancellationDisposable = new CancellationDisposable().DisposeWith(subscriptions);

            using (SynchronizationContextHelper.ScopedSet(schedulerContext))
            {
                taskBuilder(cancellationDisposable.Token, scheduler, state)
                .ContinueWith(t =>
                {
                    if (t.IsCanceled)
                    {
                        subscriptions.Disposable = null;
                    }

                    else if (t.IsFaulted)
                    {
                        subscriptions.Disposable = scheduler.Schedule(() => { t.Exception.Handle(e => e is OperationCanceledException); });
                    }

                    else
                    {
                        subscriptions.Disposable = t.Result;
                    }
                }, TaskContinuationOptions.ExecuteSynchronously);
            }

            return(subscriptions);
        }
Beispiel #2
0
        /// <summary>
        /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
        /// </summary>
        /// <param name="scheduler">Scheduler to schedule work on.</param>
        /// <param name="state">State to pass to the asynchronous method.</param>
        /// <param name="taskBuilder">Asynchronous method to run the work.</param>
        /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
        public static IDisposable ScheduleTask <TState>(
            this IScheduler scheduler, TState state,
            Func <CancellationToken, IScheduler, TState, Task> taskBuilder)
        {
            var schedulerContext = new SchedulerSynchronizationContext(scheduler);

            return(scheduler.Schedule(state, (s, st) => InvokeTask(scheduler, st, taskBuilder, schedulerContext)));
        }
Beispiel #3
0
        /// <summary>
        /// Schedulers the specified task on the specified scheduler.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="taskBuilder"></param>
        /// <returns></returns>
        public static IDisposable Schedule(this IScheduler source, Func <CancellationToken, Task> taskBuilder)
        {
            var subscriptions          = new CompositeDisposable(2);
            var cancellationDisposable = new CancellationDisposable();

            // Capture the source context before calling schedule.
            var sourceCtx = new SchedulerSynchronizationContext(source);

            // It is acceptable to use the async void pattern as long as the
            // synchronization context is not the default, i.e. executing on the thread pool,
            // where exceptions are not trapped properly.
            System.Reactive.Concurrency.Scheduler.Schedule(
                source,
                () =>
            {
                using (SynchronizationContextHelper.ScopedSet(sourceCtx))
                {
                    taskBuilder(cancellationDisposable.Token)
                    .ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            source.Schedule(() =>
                            {
                                throw t.Exception;
                            });
                        }
                    }
                                  );
                }
            }
                ).DisposeWith(subscriptions);

            cancellationDisposable.DisposeWith(subscriptions);

            return(subscriptions);
        }