Exemplo n.º 1
0
        public static IAsyncObservable <TResult> When <TResult>(IEnumerable <AsyncPlan <TResult> > plans)
        {
            if (plans == null)
            {
                throw new ArgumentNullException(nameof(plans));
            }

            return(Create <TResult>(async observer =>
            {
                var externalSubscriptions = new Dictionary <object, IAsyncJoinObserver>();
                var gate = new AsyncLock();
                var activePlans = new List <ActiveAsyncPlan>();

                var outputObserver = AsyncObserver.Create <TResult>(
                    observer.OnNextAsync,
                    async ex =>
                {
                    foreach (var subscription in externalSubscriptions.Values)
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }

                    await observer.OnErrorAsync(ex).ConfigureAwait(false);
                },
                    observer.OnCompletedAsync
                    );

                try
                {
                    foreach (var plan in plans)
                    {
                        var activatedPlan = plan.Activate(externalSubscriptions, outputObserver, async activePlan =>
                        {
                            activePlans.Remove(activePlan);

                            if (activePlans.Count == 0)
                            {
                                await outputObserver.OnCompletedAsync().ConfigureAwait(false);
                            }
                        });

                        activePlans.Add(activatedPlan);
                    }
                }
                catch (Exception ex)
                {
                    return await Throw <TResult>(ex).SubscribeAsync(observer).ConfigureAwait(false);
                }

                var d = new CompositeAsyncDisposable();

                foreach (var joinObserver in externalSubscriptions.Values)
                {
                    await joinObserver.SubscribeAsync(gate).ConfigureAwait(false);
                    await d.AddAsync(joinObserver).ConfigureAwait(false);
                }

                return d;
            }));
        }
Exemplo n.º 2
0
        private static async Task ForEachAsyncCore <TSource>(IAsyncObservable <TSource> source, Func <TSource, int, Task> onNext, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            var tcs = new TaskCompletionSource <object>();

            var subscription = new SingleAssignmentAsyncDisposable();

            using (token.Register(() =>
            {
                tcs.TrySetCanceled(token);

                subscription.DisposeAsync().AsTask().ContinueWith(t =>
                {
                    if (t.Exception != null)
                    {
                        // TODO: Trace?
                    }
                });
            }))
            {
                var i = 0;

                var o = AsyncObserver.Create <TSource>(
                    async x =>
                {
                    try
                    {
                        await onNext(x, checked (i++)).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        try
                        {
                            tcs.TrySetException(ex);
                        }
                        finally
                        {
                            await subscription.DisposeAsync().ConfigureAwait(false);
                        }
                    }
                },
                    async ex =>
                {
                    try
                    {
                        tcs.TrySetException(ex);
                    }
                    finally
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                },
                    async() =>
                {
                    try
                    {
                        tcs.TrySetResult(null);
                    }
                    finally
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                }
                    );

                //
                // NB: If any of the lines below throw, the result will go into the Task returned from the async method.
                //     There's also no need to use SubscribeSafeAsync here; the exception will propagate just fine.
                //

                var d = await source.SubscribeAsync(o).ConfigureAwait(false);

                await subscription.AssignAsync(d).ConfigureAwait(false);
            }

            await tcs.Task.ConfigureAwait(false);
        }