异步/等待Lambdas

本文关键字:Lambdas 等待 异步 | 更新日期: 2023-09-27 18:20:34

我在组合async/await以使其工作时遇到了一个奇怪的问题:我创建了一个小程序,它应该基本上处理每个动作的尝试/捕获:

    internal static void HandledAction(Action action, Info infoBar)
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            infoBar.SetError("An Exception occured: " + ex.Message);
            WriteLog(ex.StackTrace);
        }

没什么好想象的,但这是值得的,因为更改错误处理非常容易。但是,如果我想在Lambda中获得数据异步,会发生什么呢?让我们举一个简单的例子:

    private void mnuImportData_Click(object sender, RoutedEventArgs e)
    {
        ActionHelper.HandledAction(async () =>
        {
            throw new NotImplementedException("Ups");
        }, infoMain);
    }

当然,HandledAction会被调用、传递,因为它会取回指针,并且抛出异常,当然不会被处理。

我想我必须创建一个AsyncHandledAction,并将操作设置为async,但有更简单的方法来解决这个问题吗?

我想很多人都使用中央异常处理,对此有更好的解决方案吗?

提前感谢

Matthias

编辑:我创建了一个例子,它应该是我需要的:我基本上不希望我通过的整个Action是无效的,但Lambda中的一个调用是:

ActionHelper.HandledActionAsync(() =>
        {
            //elided
            CheckFileResult rslt = await excelImport.CheckFilesAsync(tmpPath);
            //elided
        }, infoMain);

当然,通过这样做,我得到了错误:

错误3"await"运算符只能在异步lambda表达式中使用。请考虑使用"async"修饰符标记此lambda表达式。

异步/等待Lambdas

原因是:操作而不是函数。自您的:

async () =>
        {
            throw new NotImplementedException("Ups");
        }

事实上是:

async void Method() { }

Func<Task>为时

async Task Method() { }

异步void将捕获SynchronizationContext.Current,当抛出异常时,它将由SynchronizationContext.Post()-发布到SynchronizationContext(在windows运行时,您可以捕获这些类型的异常)。在ASP.NET/Console application的情况下,SynchronizationContext.Current返回null,这意味着异常将传播到线程池,我不确定,但我认为不可能捕捉到它。但是,当异步方法返回Task时,异常可以通过此返回的Task封送至调用方。同样值得一提的是,异步lambda表达式总是更喜欢使用Func<Task>而不是Action的方法。一般规则是:永远不要使用async voidasync Action),除非它是"顶级方法"(在示例事件处理程序中)。

您需要一个异步版本的HandleAction

internal static async Task HandledAction(Func<Task> action, Info infoBar)
{
    try
    {
        await action();
    }
    catch (Exception ex)
    {
        infoBar.SetError("An Exception occured: " + ex.Message);
        WriteLog(ex.StackTrace);
    }
}

当然,您应该调用带有等待的方法

private async void mnuImportData_Click(object sender, RoutedEventArgs e)
{
    await ActionHelper.HandledAction(async () =>
    {
        throw new NotImplementedException("Ups");
    }, infoMain);
}