当void为返回值时,从async-await捕获异常 [英] Catching exceptions from async-await when void is the return value

查看:246
本文介绍了当void为返回值时,从async-await捕获异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现自己使用异步即发即弃方法,将void作为返回值,但一定要注意异常.

I find myself using async fire-and-forget methods using void as the return value, but DO care about exceptions.

这似乎是

It seems to be the consensus that exceptions cannot be handled properly with async-await if no reference is hold to the executing Task and void should be.. well.. avoided..

以下似乎可以完成此工作的代码缺少什么:

What am I missing in the following code that apparently seems to do the job:

class Program
{
    static void Main()
    {
        var p = new Processor();
        p.ExceptionThrown += p_ExceptionThrown;
        for (var i = 0; i < 10; i++)
            p.ProcessAsync(i);
        Console.ReadKey();
    }

    static void p_ExceptionThrown(object sender, Exception e)
    {
        Console.WriteLine("Exception caught in Main : " + e);
    }
}

class Processor
{
    public async void ProcessAsync(int iteration)
    {
        try
        {
            await Task.Run(() => Process(iteration));
        }
        catch (Exception e)
        {
            OnException(e);
        }
    }

    public void Process(int iteration)
    {
        Thread.Sleep(500);
        if(iteration == 5)
            throw new Exception("AUUCH");
    }

    public event EventHandler<Exception> ExceptionThrown;

    void OnException(Exception e)
    {
        var handler = ExceptionThrown;
        if (handler != null)
            handler(this, e);
    }
}

推荐答案

async / await关键字在被精简为IL时实际上会生成状态机,请阅读所述这里.问题在于,构建状态机时,它使用TaskTask<T>类作为返回类型,以便管理链中下一个异步操作的下一个状态.但是,将方法定义为void时,它基本上将null返回到状态机,然后一切都摆脱了.

Under the covers the async / await keywords actually generate a state-machine when they are compiled down to IL, please read about it here. The only time that you should ever use async void is on an event handler, as explained here. The issue is that when the state machine is built-out it uses the Task or Task<T> classes as the return type in order to manage the next state of the next asynchronous operation in the chain. However, when you define the method as void, it basically returns null to the state machine and then everything gets out of whack.

异步无效异常无法通过catch捕获

Exceptions from an async void can’t be caught with catch

以上引述摘自我之前指出的最佳实践文章.下面的更改确实有效,因为我已经对其进行了测试以验证它是否有效.

The quote from above is from the best practices article I pointed you to before. The below alteration does work, as I have tested it to verify that it does.

class Program
{
    static void Main()
    {
        var p = new Processor();
        p.ExceptionThrown += p_ExceptionThrown;
        for (var i = 0; i < 10; i++)
            p.ProcessAsync(i);
        Console.ReadKey();
    }

    static void p_ExceptionThrown(object sender, Exception e)
    {
        Console.WriteLine("Exception caught in Main : " + e);
    }
}

class Processor
{
    public async Task ProcessAsync(int iteration)
    {
        try
        {
            await Task.Run(() => Process(iteration));
        }
        catch (Exception e)
        {
            OnException(e);
        }
    }

    public void Process(int iteration)
    {
        Thread.Sleep(500);
        if(iteration == 5)
            throw new Exception("AUUCH");
    }

    public event EventHandler<Exception> ExceptionThrown;

    void OnException(Exception e)
    {
        var handler = ExceptionThrown;
        if (handler != null)
            handler(this, e);
    }
}

这篇关于当void为返回值时,从async-await捕获异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆