You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:40:19