Rx运算符以串行方式运行任务,最后收集异常

时间:2011-12-28 15:55:22

标签: c# .net silverlight-4.0 system.reactive

我在Silverlight 4中使用Rx来调用我的数据访问代码(没有TPL的地方)。

我想连续进行3次Web服务调用(目前不兼容)并获得结果。我曾经使用过SelectMany:

var seq = from a1 in Observable.Return(5).Delay(TimeSpan.FromSeconds(2))
          from b1 in Observable.Return(6).Delay(TimeSpan.FromSeconds(2))
          from c1 in Observable.Return(7).Delay(TimeSpan.FromSeconds(2))
          select new { a1, b1, c1 };

但我希望第二次和第三次调用仍然可以执行,即使第一次有异常。

是否有一个Rx运算符将组合序列,但只有OnException一旦所有序列完成?在功能上等同于以下代码的东西:

using System;
using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;

namespace ConsoleApplication4
{

    public class Results
    {
        public int A { get; set; }
        public int B { get; set; }
        public string C { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            new Program().Test();
        }

        public void Test()
        {

            GetResults().SubscribeOn(Scheduler.NewThread).Subscribe(
                results => Console.WriteLine("{0} {1} {2}", results.A, results.B, results.C),
                ex => Console.WriteLine(ex.ToString()),
                () => Console.WriteLine("Completed")
            );

            Console.WriteLine("Not blocking");

            Console.Read();
        }

        public IObservable<Results> GetResults()
        {
            return Observable.Create<Results>(obs =>
                {

                    var a = Observable.Return(5).Delay(TimeSpan.FromSeconds(2));
                    var b = Observable.Throw<int>(new Exception("uh oh")).Delay(TimeSpan.FromSeconds(2));
                    var c = Observable.Return("7").Delay(TimeSpan.FromSeconds(2));

                    var results = new Results();
                    var exceptions = new List<Exception>();

                    try
                    {
                        results.A = a.FirstOrDefault();
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }

                    try
                    {
                        results.B = b.FirstOrDefault();
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }

                    try
                    {
                        results.C = c.FirstOrDefault();
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }

                    obs.OnNext(results);
                    if (exceptions.Count > 0)
                        obs.OnError(new AggregateException(exceptions.ToArray()));
                    else
                        obs.OnCompleted();
                    return Disposable.Empty;
                });
        }
    }
}

1 个答案:

答案 0 :(得分:1)

怎么样:

var result = Observable.Concat(
    startObservable1().Catch(Observable.Return<TTheType>(null)),
    startObservable2().Catch(Observable.Return<TTheType>(null)),
    startObservable3().Catch(Observable.Return<TTheType>(null)));
  

是否有一个Rx运算符将组合序列,但只有OnException一旦所有序列完成?

这部分有点难,我使用这个课虽然我对此并不满意:

public class Maybe<T>
{
    public Exception Exception { get; protected set; }

    T _Value;
    public T Value {
        get {
            if (Exception != null) {
                throw Exception;
            }
            return _Value;
        }
        protected set { _Value = value; }
    }

    public static Maybe<T> AsError(Exception ex)
    {
        return new Maybe<T>() {Value = default(T), Exception = ex};
    }

    public static Maybe<T> AsValue(T value)
    {
        return new Maybe<T>() {Value = value};
    }
}

然后你可以这样做:

var result = Observable.Concat(
    startObservable1().Select(x => Maybe.AsValue(x)).Catch<T1, Exception>(x => Maybe.AsError(x)),
    startObservable2().Select(x => Maybe.AsValue(x)).Catch<T1, Exception>(x => Maybe.AsError(x)),
    startObservable3().Select(x => Maybe.AsValue(x)).Catch<T1, Exception>(x => Maybe.AsError(x)));

您可以编写自己的Maybeify()扩展方法来隐藏Select + Catch。