コード例 #1
0
ファイル: RepeatUntil.cs プロジェクト: tansir23/QFramework
            void RecursiveRun(Action self)
            {
                lock (gate)
                {
                    this.nextSelf = self;
                    if (isDisposed)
                    {
                        return;
                    }
                    if (isStopped)
                    {
                        return;
                    }

                    var current = default(IObservable <T>);
                    var hasNext = false;
                    var ex      = default(Exception);

                    try
                    {
                        hasNext = e.MoveNext();
                        if (hasNext)
                        {
                            current = e.Current;
                            if (current == null)
                            {
                                throw new InvalidOperationException("sequence is null.");
                            }
                        }
                        else
                        {
                            e.Dispose();
                        }
                    }
                    catch (Exception exception)
                    {
                        ex = exception;
                        e.Dispose();
                    }

                    if (ex != null)
                    {
                        stopper.Dispose();
                        observer.OnError(ex);
                        return;
                    }

                    if (!hasNext)
                    {
                        stopper.Dispose();
                        observer.OnCompleted();
                        return;
                    }

                    var source = e.Current;
                    var d      = new SingleAssignmentDisposable();
                    subscription.Disposable = d;

                    if (isFirstSubscribe)
                    {
                        isFirstSubscribe = false;
                        d.Disposable     = source.Subscribe(this);
                    }
                    else
                    {
                        MainThreadDispatcher.SendStartCoroutine(SubscribeAfterEndOfFrame(d, source, this, parent.lifeTimeChecker));
                    }
                }
            }
コード例 #2
0
            public IDisposable Run()
            {
                var e = default(IEnumerator <T>);

                try
                {
                    e = parent.source.GetEnumerator();
                }
                catch (Exception exception)
                {
                    OnError(exception);
                    return(Disposable.Empty);
                }

                if (parent.scheduler == Scheduler.Immediate)
                {
                    while (true)
                    {
                        bool hasNext;
                        var  current = default(T);
                        try
                        {
                            hasNext = e.MoveNext();
                            if (hasNext)
                            {
                                current = e.Current;
                            }
                        }
                        catch (Exception ex)
                        {
                            e.Dispose();
                            try { observer.OnError(ex); }
                            finally { Dispose(); }
                            break;
                        }

                        if (hasNext)
                        {
                            observer.OnNext(current);
                        }
                        else
                        {
                            e.Dispose();
                            try { observer.OnCompleted(); }
                            finally { Dispose(); }
                            break;
                        }
                    }

                    return(Disposable.Empty);
                }

                var flag = new SingleAssignmentDisposable();

                flag.Disposable = parent.scheduler.Schedule(self =>
                {
                    if (flag.IsDisposed)
                    {
                        e.Dispose();
                        return;
                    }

                    bool hasNext;
                    var current = default(T);
                    try
                    {
                        hasNext = e.MoveNext();
                        if (hasNext)
                        {
                            current = e.Current;
                        }
                    }
                    catch (Exception ex)
                    {
                        e.Dispose();
                        try { observer.OnError(ex); }
                        finally { Dispose(); }
                        return;
                    }

                    if (hasNext)
                    {
                        observer.OnNext(current);
                        self();
                    }
                    else
                    {
                        e.Dispose();
                        try { observer.OnCompleted(); }
                        finally { Dispose(); }
                    }
                });

                return(flag);
            }
コード例 #3
0
        /// <summary>
        /// Returns a task that will receive the last value or the exception produced by the observable sequence.
        /// </summary>
        /// <typeparam name="TResult">The type of the elements in the source sequence.</typeparam>
        /// <param name="observable">Observable sequence to convert to a task.</param>
        /// <param name="cancellationToken">Cancellation token that can be used to cancel the task, causing unsubscription from the observable sequence.</param>
        /// <param name="state">The state to use as the underlying task's AsyncState.</param>
        /// <returns>A task that will receive the last element or the exception produced by the observable sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="observable"/> is null.</exception>
        public static Task <TResult> ToTask <TResult>(this IObservable <TResult> observable, CancellationToken cancellationToken, object state)
        {
            if (observable == null)
            {
                throw new ArgumentNullException("observable");
            }

            var hasValue  = false;
            var lastValue = default(TResult);

            var tcs = new TaskCompletionSource <TResult>(state);

            var disposable = new SingleAssignmentDisposable();

            var ctr = default(CancellationTokenRegistration);

            if (cancellationToken.CanBeCanceled)
            {
                ctr = cancellationToken.Register(() =>
                {
                    disposable.Dispose();
                    tcs.TrySetCanceled(cancellationToken);
                });
            }

            var taskCompletionObserver = Observer.Create <TResult>(
                value =>
            {
                hasValue  = true;
                lastValue = value;
            },
                ex =>
            {
                tcs.TrySetException(ex);

                ctr.Dispose();     // no null-check needed (struct)
                disposable.Dispose();
            },
                () =>
            {
                if (hasValue)
                {
                    tcs.TrySetResult(lastValue);
                }
                else
                {
                    tcs.TrySetException(new InvalidOperationException("Strings_Linq.NO_ELEMENTS"));
                }

                ctr.Dispose();     // no null-check needed (struct)
                disposable.Dispose();
            }
                );

            //
            // Subtle race condition: if the source completes before we reach the line below, the SingleAssigmentDisposable
            // will already have been disposed. Upon assignment, the disposable resource being set will be disposed on the
            // spot, which may throw an exception. (Similar to TFS 487142)
            //
            try
            {
                //
                // [OK] Use of unsafe Subscribe: we're catching the exception here to set the TaskCompletionSource.
                //
                // Notice we could use a safe subscription to route errors through OnError, but we still need the
                // exception handling logic here for the reason explained above. We cannot afford to throw here
                // and as a result never set the TaskCompletionSource, so we tunnel everything through here.
                //
                disposable.Disposable = observable.Subscribe/*Unsafe*/ (taskCompletionObserver);
            }
            catch (Exception ex)
            {
                tcs.TrySetException(ex);
            }

            return(tcs.Task);
        }