2014-10-06 76 views
2

这里是一个什么我试图证明(以上)的简化版本:在执行低级ReactiveCommands时,ReactiveUI如何处理异常?

var reactiveCommandA = ReactiveCommand.CreateAsyncTask(_ => CanPossiblyThrowAsync()); 
reactiveCommandA.ThrownExceptions 
       .Subscribe(ex => UserError.Throw("Oh no A", ex)); 

var reactiveCommandB = ReactiveCommand.CreateAsyncTask(_ => CanAlsoPossiblyThrowAsync()); 
reactiveCommandB.ThrownExceptions 
       .Subscribe(ex => UserError.Throw("Oh no B", ex)); 

var reactiveCommandC = ReactiveCommand.CreateAsyncTask 
    (
    async _ => 
       { 
       await reactiveCommandA.ExecuteAsync(); // <= Could throw here 
       await reactiveCommandB.ExecuteAsync(); 
       DoSomethingElse(); 
       } 
    ); 

reactiveCommandC.ThrownExceptions 
       .Subscribe(ex => UserError.Throw("Oh no C", ex)); 

所以假设我的背景,实施reactiveCommandA可能会抛出异常。这没关系,因为我订购了.ThrownExceptions,理论上会通知用户并重试/失败/中止(为简洁起见,此处未显示)。所以它不会冒泡给调度员。

所以当reactiveCommandA被自己执行时,这是很棒的。但是,我有reactiveCommandC它执行reactiveCommandAreactiveCommandB。我也订阅了它的.ThrownExceptions。我遇到的问题是,如果我执行reactiveCommandCreactiveCommandA实现抛出它,它也导致reactiveCommandC炸毁。然后我通知用户两次相同的根错误,因为reactiveCommandA做它的.ThrownExceptions事情,然后reactiveCommandC做它的.ThrownExceptions事情。

那么是否有这种类型的情况的标准方法?最好是有点优雅,因为我发现现有的代码相当干净,我不想混乱或引入意大利面条。

事情我已经想到了:

  • ,围绕着try/catch块“的await ......”线和吞咽异常和退出。如果我必须做很多,看起来很丑。

  • 使用await reactiveCommandA.ExecuteAsync().Catch(Observable.Never<Unit>());虽然我认为这会导致reactiveCommandC永远不会完成,因此它永远不会再执行。

  • 使用与​​方法相同的方法,但根据我是否顺利过关成功与否(如.Catch(Observable.Return(false))。仍然要检查,如果我们可以在每个await语句之间继续返回一个布尔值。

有什么雨衣在这里做的感谢

回答

2

嗯,这是ReactiveCommand设计样的,吸的一个方面?(披露:我可以说很烂,我写的),下面是固定的懒办法它:

Observable.Merge(rxCmdA.ThrownExceptions, rxCmdB.ThrownExceptions, rxCmdC.ThrownExceptions) 
    .Throttle(TimeSpan.FromMilliseconds(250), RxApp.MainThreadScheduler) 
    .Subscribe(ex => UserError.Throw("Oh no C", ex)); 

将来我肯定想要修复这些类型的双掷事件以及其他一些关于RxCmd设计的事情。

+0

很公平,保罗。虽然不是一个超级满意的答案,但我很高兴它将在未来得到改进,我也很高兴知道我没有错过某些明显的东西。我将继续看到RxUI如何继续发展。 – 2014-10-07 16:14:29

1

我对派对有点迟到,但是这样的事情呢?

bool shouldThrow = true; 

var reactiveCommandA = ReactiveCommand.CreateAsyncTask(_ => CanPossiblyThrowAsync()); 
reactiveCommandA.ThrownExceptions 
       .Where(_ => shouldThrow) 
       .Subscribe(ex => UserError.Throw("Oh no A", ex)); 

var reactiveCommandB = ReactiveCommand.CreateAsyncTask(_ => CanAlsoPossiblyThrowAsync()); 
reactiveCommandB.ThrownExceptions 
       .Where(_ => shouldThrow) 
       .Subscribe(ex => UserError.Throw("Oh no B", ex)); 

var reactiveCommandC = ReactiveCommand.CreateAsyncTask 
    (
    async _ => 
       { 
       shouldThrow = false; 

       try 
       { 
        await reactiveCommandA.ExecuteAsync(); // <= Could throw here 
        await reactiveCommandB.ExecuteAsync(); 
       } 

       finally 
       { 
        shouldThrow = true; 
       } 
       DoSomethingElse(); 
       } 
    ); 

reactiveCommandC.ThrownExceptions 
       .Subscribe(ex => UserError.Throw("Oh no C", ex)); 

也许不是超级优雅,但它应该在理论工作

+0

谢谢,我也想到了类似的东西,尽管现在它是一个我需要记住要设置的标志。这可能是一个像例子这样的简单场景的解决方案,但如果我有很多交织在一起的命令,就会变得很笨拙。 – 2014-10-17 12:49:19