我发现自己使用异步的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);
}
}
答案 0 :(得分:0)
在async / await
关键字覆盖到IL时,实际生成状态机,请阅读here。您应该使用async void
的唯一时间是在事件处理程序上,如here所述。问题是当状态机内置时,它使用Task
或Task<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);
}
}