コード例 #1
0
        static IObservable <T> ConcatCore <T>(IEnumerable <IObservable <T> > sources)
        {
            return(Observable.Create <T>(observer =>
            {
                var isDisposed = false;
                var e = sources.AsSafeEnumerable().GetEnumerator();
                var subscription = new SerialDisposable();
                var gate = new object();

                var schedule = Scheduler.DefaultSchedulers.TailRecursion.Schedule(self =>
                {
                    lock (gate)
                    {
                        if (isDisposed)
                        {
                            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)
                        {
                            observer.OnError(ex);
                            return;
                        }

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

                        var source = e.Current;
                        var d = new SingleAssignmentDisposable();
                        subscription.Disposable = d;
                        d.Disposable = source.Subscribe(observer.OnNext, observer.OnError, self); // OnCompleted, run self
                    }
                });

                return new CompositeDisposable(schedule, subscription, Disposable.Create(() =>
                {
                    lock (gate)
                    {
                        isDisposed = true;
                        e.Dispose();
                    }
                }));
            }));
        }
コード例 #2
0
        public static IObservable <TResult> Zip <TLeft, TRight, TResult>(this IObservable <TLeft> left, IObservable <TRight> right, Func <TLeft, TRight, TResult> selector)
        {
            return(Observable.Create <TResult>(observer =>
            {
                var gate = new object();
                var leftQ = new Queue <TLeft>();
                bool leftCompleted = false;
                var rightQ = new Queue <TRight>();
                var rightCompleted = false;

                Action dequeue = () =>
                {
                    TLeft lv;
                    TRight rv;
                    TResult v;
                    if (leftQ.Count != 0 && rightQ.Count != 0)
                    {
                        lv = leftQ.Dequeue();
                        rv = rightQ.Dequeue();
                    }
                    else if (leftCompleted || rightCompleted)
                    {
                        observer.OnCompleted();
                        return;
                    }
                    else
                    {
                        return;
                    }
                    try
                    {
                        v = selector(lv, rv);
                    }
                    catch (Exception ex)
                    {
                        observer.OnError(ex);
                        return;
                    }
                    observer.OnNext(v);
                };

                var lsubscription = left.Synchronize(gate).Subscribe(x =>
                {
                    leftQ.Enqueue(x);
                    dequeue();
                }, observer.OnError, () =>
                {
                    leftCompleted = true;
                    if (rightCompleted)
                    {
                        observer.OnCompleted();
                    }
                });


                var rsubscription = right.Synchronize(gate).Subscribe(x =>
                {
                    rightQ.Enqueue(x);
                    dequeue();
                }, observer.OnError, () =>
                {
                    rightCompleted = true;
                    if (leftCompleted)
                    {
                        observer.OnCompleted();
                    }
                });

                return new CompositeDisposable {
                    lsubscription, rsubscription, Disposable.Create(() =>
                    {
                        lock (gate)
                        {
                            leftQ.Clear();
                            rightQ.Clear();
                        }
                    })
                };
            }));
        }
コード例 #3
0
        public static IObservable <IList <T> > Zip <T>(params IObservable <T>[] sources)
        {
            return(Observable.Create <IList <T> >(observer =>
            {
                var gate = new object();
                var length = sources.Length;
                var queues = new Queue <T> [length];
                for (int i = 0; i < length; i++)
                {
                    queues[i] = new Queue <T>();
                }
                var isDone = new bool[length];

                Action <int> dequeue = index =>
                {
                    lock (gate)
                    {
                        if (queues.All(x => x.Count > 0))
                        {
                            var result = queues.Select(x => x.Dequeue()).ToList();
                            observer.OnNext(result);
                            return;
                        }

                        if (isDone.Where((x, i) => i != index).All(x => x))
                        {
                            observer.OnCompleted();
                            return;
                        }
                    }
                };

                var subscriptions = sources
                                    .Select((source, index) =>
                {
                    var d = new SingleAssignmentDisposable();

                    d.Disposable = source.Subscribe(x =>
                    {
                        lock (gate)
                        {
                            queues[index].Enqueue(x);
                            dequeue(index);
                        }
                    }, ex =>
                    {
                        lock (gate)
                        {
                            observer.OnError(ex);
                        }
                    }, () =>
                    {
                        lock (gate)
                        {
                            isDone[index] = true;
                            if (isDone.All(x => x))
                            {
                                observer.OnCompleted();
                            }
                            else
                            {
                                d.Dispose();
                            }
                        }
                    });

                    return d;
                })
                                    .ToArray();

                return new CompositeDisposable(subscriptions)
                {
                    Disposable.Create(() =>
                    {
                        lock (gate)
                        {
                            foreach (var item in queues)
                            {
                                item.Clear();
                            }
                        }
                    })
                };
            }));
        }
コード例 #4
0
        public static IObservable <TSource> Catch <TSource>(this IEnumerable <IObservable <TSource> > sources)
        {
            // this code is borrowed from RxOfficial(rx.codeplex.com) and modified
            return(Observable.Create <TSource>(observer =>
            {
                var gate = new object();
                var isDisposed = false;
                var e = sources.GetEnumerator();
                var subscription = new SerialDisposable();
                var lastException = default(Exception);

                var cancelable = Scheduler.CurrentThread.Schedule(self =>
                {
                    lock (gate)
                    {
                        var current = default(IObservable <TSource>);
                        var hasNext = false;
                        var ex = default(Exception);

                        if (!isDisposed)
                        {
                            try
                            {
                                hasNext = e.MoveNext();
                                if (hasNext)
                                {
                                    current = e.Current;
                                }
                                else
                                {
                                    e.Dispose();
                                }
                            }
                            catch (Exception exception)
                            {
                                ex = exception;
                                e.Dispose();
                            }
                        }
                        else
                        {
                            return;
                        }

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

                        if (!hasNext)
                        {
                            if (lastException != null)
                            {
                                observer.OnError(lastException);
                            }
                            else
                            {
                                observer.OnCompleted();
                            }
                            return;
                        }

                        var d = new SingleAssignmentDisposable();
                        subscription.Disposable = d;
                        d.Disposable = current.Subscribe(observer.OnNext, exception =>
                        {
                            lastException = exception;
                            self();
                        }, observer.OnCompleted);
                    }
                });

                return new CompositeDisposable(subscription, cancelable, Disposable.Create(() =>
                {
                    lock (gate)
                    {
                        e.Dispose();
                        isDisposed = true;
                    }
                }));
            }));
        }