从异步 Lambda 抛出的异常捕获

17

我正在尝试编写一个方法,它尝试执行一个操作,但会捕获任何引发的异常。

我的第一次尝试如下:

public static void SafeExecute(Action actionThatMayThrowException) {
    try {
        actionThatMayThrowException();
    } catch {
        // noop
    }
}

当使用同步操作调用时起作用的是:

SafeExecute(() => { 
    throw new Exception(); 
});

然而,当使用异步操作调用时会失败:

SafeExecute(async () => { 
    await Task.FromResult(0);
    throw new Exception(); 
});

是否有可能编写一个可以处理这两种情况的方法?


你正在使用哪个框架? - Neel
1个回答

21

为了正确处理async委托,您不应该使用Action(这将导致lambda表达式成为async void,这是危险的,应该避免),您应该使用Func<Task>来能够await它:

public static async Task SafeExecute(Func<Task> asyncActionThatMayThrowException)
{
    try
    {
        await asyncActionThatMayThrowException();
    }
    catch
    {
        // noop
    }
}

这将解决async的情况,但不适用于同步情况。你不能使用一个方法同时解决两种情况。要做到这一点,你需要一个不同的方法,但它仍然可以调用async方法以实现重用:

private static readonly Task<object> _completedTask = Task.FromResult<object>(null);

public static void SafeExecute(Action actionThatMayThrowException)
{
    SafeExecute(() =>
    {
        actionThatMayThrowException();
        return _completedTask;
    });
}

我不建议以这种方式忽略未处理的异常。您应该考虑至少记录异常。


我才意识到我的一些单元测试受到了这种行为的影响(基本上是失败的Assert被吞掉了),令人惊讶的是,尽管经过了这么长时间,仍然没有关于将异步lambda分配给Action的警告。 - Dylan Nicholson
1
好的,为什么异步 Lambda 在调用线程上抛出异常? - ed22

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接