从 RxUi 7 中的视图与 ThrownExceptions 交互的正确方法

Proper way to interact with ThrownExceptions from the view in RxUi 7

我正在尝试了解如何在 RxUi 7 中使用 Interaction<TInput, TOutput> 来显示确认警报。阅读 docs 之后,我想到了这个:

ViewModel

public ReactiveCommand<Unit, Unit> Save { get; }
public Interaction<Exception, bool> ConfirmError;

Save
    .ThrownExceptions
    .Subscribe(ex => ConfirmError
                       .Handle(ex)
                       .Where(retry => retry == true)
                       .SelectMany(_ => Save.Execute(Unit.Default))
                       .Subscribe()
                       .AddTo(disposables))
    .AddTo(disposables);

查看

this
    .ViewModel
    .ConfirmError
    .RegisterHandler(async interaction =>
    {
        var retry = await DisplayAlert("Confirm", 
                                       $"Something went wrong: {interaction.Input.Message}. Do you want to retry?", 
                                       "Yes", 
                                       "No");
        interaction.SetOutput(retry);
    })
    .AddTo(disposables);

我的代码可以正常工作,但我不确定确认完成后我是否正确执行了命令。我还认为对于一个简单的警告框来说代码太多了,我正在寻找一种合适的方法来做到这一点。 如何简化?

第二个问题是:

如果我需要处理不止一种 Exception 类型(即:服务错误、连接错误),检查它的正确位置在哪里?

我认为您的代码基本上没问题,除了一件事 - 您正在另一个 Subscribe 中进行 Subscribe 调用,IMO 是一种代码味道。要摆脱它,您可以这样写:

Save
    .ThrownExceptions
    .SelectMany(ConfirmError.Handle)
    .Where(retry => retry == true)
    .SelectMany(_ => Save.Execute(Unit.Default))
    .Subscribe()
    .AddTo(disposables);

这可以通过使用 InvokeCommand helper:

稍微提高可读性 (?)
Save
    .ThrownExceptions
    .SelectMany(ConfirmError.Handle)
    .Where(retry => retry == true)
    .Select(_ => Unit.Default)
    .InvokeCommant(Save)
    .AddTo(disposables);

N.B。我没有玩过 RxUI 7.0,所以我将流更改为包含单元的流是一个大胆的猜测。

I also think it´s way too much code for a simple alert box

嗯,这是一个警告框一个重试逻辑。我不确定你是否可以在 RxUI 中使用它比这更简单。

If I need to handle more than one Exception type (ie: service error, connection error), where is the right place to check it?

就个人而言,我不会考虑 exception 类型,而是考虑您希望与实际用户交互的方式。毕竟,您可能不想向他显示堆栈跟踪。

一种方法是为不同类型的用户交互(MessageInteractionYesNoInteraction 等)单独 Interactions,这将允许您区分例如需要用户输入和 toast 消息的操作。另一种方法是将所有可能的问题定义为枚举(ConnectionTimeoutServiceError 等),将可能的解决方案定义为另一个问题(RetryAbort、.. .) 然后在你的 ViewModel 中有一个 Interaction<ProblemEnum, ResolutionEnum>。这样,处理错误的代码将存储在一个地方。这种方法的缺点是处理逻辑将在视图中,因此测试起来会困难得多。

我建议您尝试并报告我的想法在实践中的效果:)