如何异步地使用UserError处理程序

本文关键字:UserError 处理 程序 何异步 异步 | 更新日期: 2023-09-27 17:53:35

大多数(如果不是全部)示例在线注册一个处理程序,但随后返回一个离散的Observable值(即Observable.Return(RecoveryOptionResult.CancelOperation))。对于一个正确的实现,最好将RecoveryOptions列表作为按钮列表(或类似的东西)呈现给用户,并将流量控制传递给用户。

我正在努力的是如何等待一个按钮由用户点击(或者更具体地说,如何等待RecoveryOption命令之一有其RecoveryResult集)。

我设法hack一些东西在一起,这个,但我不能想象这种方式是正确的。由于缺乏使用reactiveui的经验,我无法将监控ReactiveList<IRecoveryCommand>的正确方法概念化。

下面是我的代码。

// UserError.RegisterHandler(x => HandleErrorAsync(x));
private async Task<RecoveryOptionResult> HandleErrorAsync(UserError error)
{
    // present error UI...
    // use ReactiveCommand's IsExecuting observable to monitor changes (since RecoverResult is not an observable)
    // is there a better way to do this??? this seems sub-optimal
    await error.RecoveryOptions
        .Select(x => x.IsExecuting)
        .Merge()
        .Where(_ => error.RecoveryOptions.Any(x => x.RecoveryResult.HasValue))
        .FirstAsync();
    // recovery option was clicked in the UI
    // get the recovery option that was chosen
    return error.RecoveryOptions
        .Where(x => x.RecoveryResult.HasValue)
        .Select(x => x.RecoveryResult.Value)
        .First();
}
主要问题是RecoveryResult 不是可观察的。所以我必须监视IsExecuting可观察的,然后检查RecoveryResult的值。然而,似乎一定有更好的方法来做到这一点。

如何异步地使用UserError处理程序

今天再看一遍,我注意到我不能观察到RecoveryResult的原因是因为RecoveryOptionsReactiveList<IRecoveryCommand>, IRecoveryCommand是不可观察的。解决这个问题的简单方法是假设所有的恢复选项实际上是RecoveryCommand对象(可观察的),但更合适的答案是基于IRecoveryCommand合约生成一个可观察的流。

我们可以调整RxUI文档中关于恢复选项的代码来支持RxUI 6.5,方法如下:

public static IObservable<RecoveryOptionResult> GetResultAsync(this UserError This, RecoveryOptionResult defaultResult = RecoveryOptionResult.CancelOperation)
{
    return This.RecoveryOptions.Any() ?
        This.RecoveryOptions
            .Select(x => x.IsExecuting
                .Skip(1) // we can skip the first event because it's just the initial state
                .Where(_ => x.RecoveryResult.HasValue) // only stream results that have a value
                .Select(_ => x.RecoveryResult.Value)) // project out the result value
            .Merge() // merge the list of command events into a single event stream
            .FirstAsync() : //only consume the first event
        Observable.Return(defaultResult);
}

如果你想支持任何类型的IRecoveryCommand,这个扩展方法是必需的,因为它的可观察对象流基于它所知道的仅有的两个可观察对象之一。但是,如果您可以确定您只处理RecoveryCommand对象,则可以执行以下操作:

public static IObservable<RecoveryOptionResult> GetResultAsync(this UserError This, RecoveryOptionResult defaultResult = RecoveryOptionResult.CancelOperation)
{
    return This.RecoveryOptions.Any() ?
        This.RecoveryOptions
            .Cast<RecoveryCommand>()
            .Select(x => x // our command is now observable
                // we don't Skip(1) here because we're not observing a property any more
                .Where(_ => x.RecoveryResult.HasValue)
                .Select(_ => x.RecoveryResult.Value))
            .Merge()
            .FirstAsync() :
        Observable.Return(defaultResult);
}

我将把这个答案留到下一段时间,希望@paul-betts可以确认或否认这是合适的策略。