【问题标题】:Exception handling outside of Task任务之外的异常处理
【发布时间】:2015-07-03 03:35:02
【问题描述】:

刚刚注意到奇怪的事情:要在新任务的调用者中捕获异常,必须将 lambda 标记为异步!?即使 delegate 根本没有 await 操作符,真的有必要吗?

    try
    {
        //Task.Run(() =>      // exception is not caught!
        Task.Run(async () =>  // unnecessary async!?!   
        {
            throw new Exception("Exception in Task");
        }).Wait();
    }
    catch (Exception ex)
    {
        res = ex.Message;
    }

为什么需要异步操作符? 我能找到的所有文档都告诉我,delegate 不能返回 Void 并且 Task 必须等待异常传播给调用者。

添加完整代码:

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        p.Run();
    }

public void Run()
{
    string result;

    try
    {
        result = OnSomeEvent((s, ea) => RunSomeTask());
    }
    catch (Exception ex) // Try to catch unhandled exceptions here!
    {
        result = ex.Message;
    }

    Console.WriteLine(result);
    Console.ReadKey();
}

// Some other Framework bult-in event (can not change signature)
public string OnSomeEvent(EventHandler e)
{
    e.Invoke(null, new EventArgs());
    return "OK";
}

private async Task RunSomeTask()
{
    await Task.Run(async () => // do not need async here!!!
    //await Task.Run(() =>     // caller do not catches exceptions (but must)
    {
        throw new Exception("Exception in Task1");
    });
}
}

所以问题是如何抓住前任。没有异步关键字???

【问题讨论】:

  • 您不需要使用async - 我怀疑抛出异常会破坏委托类型推断。尝试明确指定委托类型。
  • 你说异常没有被捕获!当不使用异步时。但确实被抓住了。这是您的实际代码吗?
  • @Lee 是正确的。我记得几个月前读过关于这个确切主题的副本。抛出异常会改变匿名委托的返回类型。
  • @SriramSakthivel,更新了实际代码。
  • 这两种情况会发生什么?你说的作品是什么意思?你能说出你在这两种情况下观察到的行为,而不是说有效吗?

标签: c# task-parallel-library


【解决方案1】:

返回Task 的方法(例如Task.Runasync 方法)将对返回的Task 设置任何异常。以某种方式观察该异常取决于您。通常这是使用await 完成的,如下所示:

await Task.Run(() => { throw ... });

在你的情况下,问题出在这一行:

result = OnSomeEvent((s, ea) => RunSomeTask());

在这段代码中,RunSomeTask 正在返回一个 Task,并且永远不会等待 Task。为了观察异常,你应该await那个任务。

【讨论】:

  • 你建议把这个'await'操作符放在哪里?因为以这种方式编辑它result = OnSomeEvent(async (s, ea) => await RunSomeTask()); 不要抓住前任。或者,它变成了返回 'void' 的 lambda。
  • @Arvis:你必须重新考虑你的解决方案。您现在要做的是同步异步,这是一种众所周知的反模式。您必须使您的代码完全异步,或者将任务保存在某个地方并在以后对其做出反应。
【解决方案2】:

使用async/await 时,异常会在await 的位置自动解包。当使用Task.Wait() 时,任何异常从Task 出来时都会被包装,因此获取信息需要您深入研究Task.Exception 属性,因为它们不会向上传播调用堆栈。

https://dotnetfiddle.net/MmEXsT

【讨论】:

  • 在特殊情况下,无论我使用“等待”还是“等待”。我都测试了。
  • 完全忘记它在一个属性中 - 因此更新了我的分析器
猜你喜欢
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多