最近在做一个功能需要传递一个委托作为回调逻辑处理,但在使用中定义了async ()=>来处理awaiter逻辑那就存在一个安全问题了。了解async/awaiter的朋友一定清楚async void函数带来的致命风险!
async void会阻断异常路由,即当前函数没有try的情况下出现异常这类异常都是全局未捕获异常会导致程序直接闪退!代码如下:
class Program
{
static void Main(string[] args)
{
OnRun(async () =>
{
await Task.Delay(1000);
throw new Exception("error!");
});
Console.Read();
}
private static void OnRun(Action action)
{
try
{
action();
}
catch (Exception e_)
{
Console.WriteLine(e_.Message);
}
}
}
以上OnRun方法中的Try显然是无法获捕获到async ()=>函数里的异常的,而这程序运行的最终结果抛出异常闪退!
实际应用中不使用async ()=>或要求使用者在async ()=>方法定义try来避免这些问题显然也是不可能的事情。
应用中Task是支持这种写法的,而这写法从框架设计角度上来说调用应该是安全的,所以看了一下 Task.Run方法;发现其实.net core的编译器早已经处理了这些问题。
public static Task Run(Func<Task?> function, CancellationToken cancellationToken);
public static Task Run(Func<Task?> function);
public static Task Run(Action action, CancellationToken cancellationToken);
public static Task Run(Action action);
编译器会把async ()=>路由于Run(Func<Task?> function)的函数版本中,这样问题就好解决了。
class Program
{
static void Main(string[] args)
{
OnRun(async () =>
{
await Task.Delay(1000);
throw new Exception("error!");
});
Console.Read();
}
private static async void OnRun(Func<Task?> action)
{
try
{
await action();
}
catch (Exception e_)
{
Console.WriteLine(e_.Message);
}
}
private static void OnRun(Action action)
{
try
{
action();
}
catch (Exception e_)
{
Console.WriteLine(e_.Message);
}
}
}
这样async ()=>异常处理就能还捕获处理,不会引起程序闪退问题。
注意
在代码中尽可能不要定义async void函数,可以使用async Task来代替,除非你对async void函数危害和如何规避风险有所了解。
BeetleX
开源跨平台通讯框架(支持TLS)
提供高性能服务和大数据处理解决方案
https://beetlex.io