【问题标题】:Passing exception from Task.Run to await properly and Debugger从 Task.Run 传递异常以正确等待和调试器
【发布时间】:2016-10-19 18:29:56
【问题描述】:

这是抛出异常的任务。

public Task<SensorReading> ReadSensorsAsync(int cell)
{
    return Task.Run(() => {
            throw new ArgumentNullException();
...

这是async 方法:

private async void TimerCallback(object state)
{
    try
    {
        var tasksRead = Enumerable.Range(3, 35).Select(i => sensorReader.ReadSensorsAsync(i)).ToList();
        await Task.WhenAll(tasksRead);
        var r = tasksRead.Select(x => x.Result).ToList();
        var taskRecordREsult = RecordReadingAsync(r).Result;
    }
    catch(Exception e)
    {
        // expecting to catch everything here
    }
}

我所期待的是异常会在await 部分代码中处理。但是,我在 Visual Studio 调试器中遇到了未处理的异常。

问题 - 如何正确地将所有类型的异常从 Task.Run 传递到等待部分?

【问题讨论】:

  • 如果你点击“继续”,它那么会被抓住吗?这是我经常看到的......
  • 顺便说一句,您可以在示例中包含“await”表达式吗?
  • @JonSkeet:是的,“继续”将我带到等待,但我不希望 VS 告诉我每次Task.Run 发生某些事情时我都有“未处理的异常”。跨度>
  • @alexm:我已经更新了代码
  • 所以“无法将异常从Task.Run传递给await”的标题有点不准确......它真的是“当任务抛出异常时调试器烦人地中断”

标签: c# exception async-await task-parallel-library task


【解决方案1】:

一种可能的解决方案是将您的 Task.Run lambda 提取到一个独立的方法中,并向其中添加 [DebuggerStepThrough] 属性。理论上(我还没有测试过),这将抑制调试器中的第一个异常,并允许稍后捕获它。它不漂亮,但它应该可以解决问题。

【讨论】:

  • 问题不仅在于调试器本身,还在于处理更深层次的异常。所以第一个问题仍然存在——处理Task.Run中发生的所有异常是否正确?
  • 在 .NET 4.0 中,必须处理或至少观察 Task.Run 中引发的异常。两种主要模式要么在 Task.Run 中放置 Try..Catch 块,要么通过检查 Task.IsFaulted 来检查运行结果(例如在 .ContinueWith() 块中)。在 .NET 4.5 中,使用 Await 将允许将异常正确地带回原始线程。
  • 在您为不返回结果的过程启动 Task.Run 的情况下,如果 Task 中有未处理的异常,它可能会关闭整个应用程序(至少确实如此)在 Windows 窗体中),因为不允许在后台线程中处理异常。
【解决方案2】:

试试这个程序,看看你是否仍然会崩溃..

它对我有用

class Program
{
    static void Main(string[] args)
    {
        new Program().TimerCallback();
    }

    public Task<string> ReadSensorsAsync(string cell)
    {
        return Task.Run(() =>
        {
            if(cell == null) throw new ArgumentNullException();
            return cell;
        });
    }

    public Task<string> RecordReadingAsync(IEnumerable<string> cell)
    {
        return Task.Run(() =>
        {
            return string.Join(",", cell);
        });
    }

    public async void TimerCallback()
    {
        try
        {
            var tasksRead = new string[] { "1", null, "3" }.Select(s => ReadSensorsAsync(s));
            var taskRecordResult = await RecordReadingAsync(await Task.WhenAll(tasksRead));
            Debugger.Log(1, "test", taskRecordResult);
        }
        catch (Exception e)
        {
            //catches here
            Debugger.Log(1, "test", e.Message ?? e.ToString());
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 2012-11-12
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多