如何使用异步方法捕获 ReactiveCommand 中的异常

How to catch exceptions in ReactiveCommand with async method

我有一个与 非常相似的问题。但是,在我的例子中,我创建了一个在执行时调用异步方法的 ReactiveCommand。 ThrownExceptions observable 似乎没有管道任何异常,无论它们被抛出在哪里(直接在方法中或在它启动的任务中)。

我写了一个最简单的例子来证明这一点。我知道 ThrownExceptions 并不能捕获所有内容,但我不知道它不适用于哪些情况或如何正确处理这些异常。

using ReactiveUI;
using System;
using System.Reactive;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static void Main()
        {
            var test = new TestClass();
   
            while (Console.ReadKey().Key == ConsoleKey.Enter)
            {
                test.Command.Execute().Subscribe();
            }

            Console.ReadKey();
        }
    }


    public class TestClass
    {
        public TestClass()
        {
            Command = ReactiveCommand.Create(() => RunCommand());
            Command.ThrownExceptions.Subscribe(ex => HandleException(ex));
        }
   
        public ReactiveCommand<Unit, Task> Command { get; private set; }

        private async Task RunCommand()
        {
            //throw new Exception("will not be handled");

            //await Task.Run(() => throw new Exception("will also not be handled"));
        }

        private void HandleException(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

回答我自己的问题:必须使用 CreateFromTask 方法而不是 Create 方法创建调用异步方法的命令。

此外,如果通过订阅它的 Execute 可观察命令来执行命令,则不会捕获异常。必须改用 ICommand 接口的 Execute 方法(命令应该使用此接口公开给 public)。

我已将我的演示项目更改如下:

class Program
{
    static void Main()
    {
        var test = new TestClass();
   
        while (Console.ReadKey().Key == ConsoleKey.Enter)
        {
            (test.Command as ICommand).Execute(null);
        }

        Console.ReadKey();
    }
}


public class TestClass
{
    public TestClass()
    {
        Command = ReactiveCommand.CreateFromTask(RunCommand);
        Command.ThrownExceptions.Subscribe(ex => HandleException(ex));
    }
   
    public ReactiveCommand<Unit, Unit> Command { get; private set; }

    private async Task RunCommand()
    {
        //throw new Exception("will be handled");

        await Task.Run(() => 
        {
            throw new Exception("will also be handled");
        });
    }

    private void HandleException(Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}