简体   繁体   English

当void为返回值时,从async-await捕获异常

[英]Catching exceptions from async-await when void is the return value

I find myself using async fire-and-forget methods using void as the return value, but DO care about exceptions. 我发现自己使用异步即弃方法,将void作为返回值,但请务必注意异常。

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.. 似乎已经达成共识 ,即如果没有对执行中的Task的引用,则无法使用async-await正确处理异常,因此应避免void。

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);
    }
}

Under the covers the async / await keywords actually generate a state-machine when they are compiled down to IL, please read about it here . 在幕后,当async / await关键字被编译为IL时,它们实际上会生成一个状态机,请在此处阅读。 The only time that you should ever use async void is on an event handler, as explained here . 你应该永远使用唯一的一次async void是一个事件处理程序,如解释在这里 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. 问题在于,构建状态机时,它使用TaskTask<T>类作为返回类型,以便管理链中下一个异步操作的下一个状态。 However, when you define the method as void, it basically returns null to the state machine and then everything gets out of whack. 但是,当您将方法定义为void时,它基本上会向状态机返回null ,然后一切都会摆脱困境。

Exceptions from an async void can't be caught with catch 异步void的异常无法被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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM