Task.Factory.StartNew中抛出的异常无法传递至调用方问题咨询
异常无法捕获的原因及修复方案
核心原因
你遇到的问题本质是Task.Factory.StartNew不兼容异步委托:
- 当你给
Task.Factory.StartNew传入async () => { ... }这种异步lambda时,它会将其视为返回Task的普通同步委托,因此实际返回的类型是Task<Task>(外层任务包装内层异步任务)。 - 外层的
await仅等待外层Task完成,而外层任务会在异步lambda开始执行后立即结束,不会等待内部的DecryptStreamAsync执行完毕。内部任务抛出的KeyException被包裹在外层Task<Task>的结果中,无法被外层的try-catch捕获。
你在ASP.NET Core中没遇到类似问题,是因为通常不会用Task.Factory.StartNew启动异步任务,而是直接await异步方法或使用Task.Run(后者能正确处理异步委托)。
修复方案
有三种可行的修复方式,按需选择:
1. 改用Task.Run(推荐)
Task.Run能正确识别异步委托,返回的Task会等待整个异步流程完成,异常可正常传播:
protected override async void Btn_Start_OnClick(object sender, EventArgs e) { try { await Task.Run(async () => { await _crypto.DecryptStreamAsync(key, _io.FSIn, _io.FSOut, _tokenSource.Token); }, _tokenSource.Token); // UI相关方法 } catch (KeyException) { // 处理异常 } }
2. 保留StartNew并调用Unwrap
如果必须使用TaskCreationOptions.LongRunning选项,可通过Unwrap()方法将Task<Task>转换为代表内部任务完成的Task:
protected override async void Btn_Start_OnClick(object sender, EventArgs e) { try { await Task.Factory.StartNew(async () => { await _crypto.DecryptStreamAsync(key, _io.FSIn, _io.FSOut, _tokenSource.Token); }, _tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Current).Unwrap(); // UI相关方法 } catch (KeyException) { // 处理异常 } }
3. 直接异步调用(最优,若无需额外线程)
由于DecryptStreamAsync本身是异步IO操作,不会阻塞UI线程,可直接调用并等待,无需额外启动任务:
protected override async void Btn_Start_OnClick(object sender, EventArgs e) { try { await _crypto.DecryptStreamAsync(key, _io.FSIn, _io.FSOut, _tokenSource.Token); // UI相关方法 } catch (KeyException) { // 处理异常 } }
内容的提问来源于stack exchange,提问作者Zombies are Real
相关产品推荐
相关产品推荐

