当void为返回值

时间:2016-01-12 09:02:04

标签: c# async-await

我发现自己使用异步的fire-and-forget方法,使用void作为返回值,但DO关心异常。

似乎是consensus如果没有对执行任务执行任何引用而无法使用async-await处理异常,那么void应该......好吧..避免..

我在下面的代码中遗漏了什么,显然似乎可以完成这项任务:

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

1 个答案:

答案 0 :(得分:0)

async / await关键字覆盖到IL时,实际生成状态机,请阅读here。您应该使用async void的唯一时间是在事件处理程序上,如here所述。问题是当状态机内置时,它使用TaskTask<T>类作为返回类型,以便管理链中下一个异步操作的下一个状态。但是,当您将方法定义为void时,它基本上会将null返回给状态机,然后一切都会失败。

  

无法通过catch

捕获异步void的异常

上面的引用来自我之前指出的最佳实践文章。以下更改确实有效,因为我已对其进行测试以验证确实存在。

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