返回值是void的异步方法,绝对不能向外抛出异常,否则该异常会直接抛到CLR,导致进程终止。
下面的代码不会导致进程终止
public static async void Test()
{
try
{
await AsyncMethodWillThrowException(); // await后面的异步方法抛出的异常能在内部被catch
throw new Exception(); // 这里抛出的异常也能被catch
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
下面的代码会导致进程终止
static void Main(string[] args)
{
try
{
Test(); // async void 抛出的异常无法被catch
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.Read();
}
public static async void Test()
{
await AsyncMethodWillThrowException();
throw new Exception();
}
小结:
1. 异步方法的返回类型一般都时Task或Task<T>,返回值引用相当于一种承诺,在需要的时候,可以用来等待异步方法完成,检查异步方法执行成功与否,以及获取异步方法的执行结果即其返回值,如果异步方法的返回值是void,则此异步方法不对外提供"承诺书",此异步方法就像泥牛入海消失在人间,外界也无法得知其一切进展信息,所以当void 异步方法抛出异常时,外界无从得知,如果什么也不做,忽略异常让程序带病继续运行下去,这是危险的,所以CLR知道别人管不了它,所以索性直接进程终止!
2.由上述可知,永远不应该让异步方法的返回类型是void,但是这种情况避免不了,比如很多内置的事件处理程序是返回值为void的同步方法,不可避免的会调用异步方法,如按钮的点击事件。这种情况推荐的处理措施就是务必在最外围加一个大大的try catch,在catch中记录异常即可。