【问题标题】:Exceptions are not caught with ContinueWith?ContinueWith 不会捕获异常?
【发布时间】:2016-01-09 15:39:59
【问题描述】:

使用 Visual Studio 2015,以 FW 4 为目标(在 FW 4 下测试不可观察的异常):

我期待这个代码:

static void Main(string[] args)
{

    try
    {
        Task.Factory.StartNew(() => Console.WriteLine(1))
        .ContinueWith(t => Thread.Sleep(1000))
        .ContinueWith(t => Console.WriteLine(2))
        .ContinueWith(t => Thread.Sleep(1000))
        .ContinueWith(t => { throw new Exception("aaaa"); })
        .ContinueWith(t => Console.WriteLine(3));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);

    }
    GC.Collect();
    GC.Collect();
    Console.ReadLine();
}

向我展示异常。

我知道我可以通过 T.Wait() 或在最后一个任务中使用 t.Exception 看到它 - 但为什么我在这里没有看到异常?

我知道异常处理机制在 4.5 中改变了,为了获得旧的机制,我应该添加:

 <ThrowUnobservedTaskExceptions enabled="true"/>

我做了什么:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
  <runtime>
    <ThrowUnobservedTaskExceptions enabled="true"/>
  </runtime>
</configuration>

但结果还是:

问题:

为什么我没有看到异常?

值得一提的是,我确实在调试模式下看到了异常:

【问题讨论】:

  • 你试过throw new BackoffException("aaaaa");
  • 它也可能是一个内部异常。如果是这样,您需要检查内部异常,称为聚合异常...
  • 您可以检查的另一件事。在不调试或禁用“仅我的代码”的情况下运行(工具 -> 选项 -> 调试 -> 常规)...
  • @Codexer 已经禁用了。

标签: c# continuewith


【解决方案1】:

您不能期望这段代码抛出异常,因为try 子句中的所有语句所做的只是描述了一个延续模式。 StartNewContinueWith 方法不会引发异常。所以在后台任务中抛出异常时,代码执行早就离开了这个try语句。如果在程序启动后大约 2 秒后抛出异常,则在 Console.Readline 语句上停止执行。

正如您已经发现的那样,您需要等待任务完成才能访问异常或继续本身。

现在,您的应用程序之所以不会因未观察到的异常而死掉,是因为没有发生垃圾收集。当任务被垃圾收集时,未观察到的异常将破坏您的应用程序域。但是当你强制 GC 时,还没有抛出异常,任务也没有完成,所以它不符合垃圾收集的条件。

确保将GC.Collect 调用放在 Console.ReadLine 方法之后,然后再放置另一个Console.ReadLine

Task.Factory.StartNew(() => Console.WriteLine(1))
    .ContinueWith(t => Thread.Sleep(1000))
    .ContinueWith(t => Console.WriteLine(2))
    .ContinueWith(t => Thread.Sleep(1000))
    .ContinueWith(t => { throw new Exception("aaaa"); })
    .ContinueWith(t => Console.WriteLine(3));

Console.ReadLine();
GC.Collect();
GC.Collect();
Console.ReadLine();

显然应该存在以下配置开关:

<ThrowUnobservedTaskExceptions enabled="true"/>

【讨论】:

  • 不,他没有错。但是你GC.Collecting 太早了。我已经用这些信息更新了我的答案。
  • Now Works as expected ,在您最后一次编辑之后:-)。谢谢。
【解决方案2】:

你有没有尝试连接到TaskScheduler.UnobservedTaskException,它被抓到了吗?

[HandleProcessCorruptedStateExceptions]
public static void SetupUnobservedTaskExceptionHandling(ILogger logger)
{
    logger.Debug("Setting up unobserved task exception handling...");
    TaskScheduler.UnobservedTaskException += (sender, args) =>
    {
        var e = args.Exception;
        logger.ErrorFormat("TaskScheduler Unobserved Exception - Message: {0}", e.Message);
        logger.ErrorFormat("TaskScheduler Unobserved Exception - Inner exception: {0}", e.InnerException);
        logger.ErrorFormat("TaskScheduler Unobserved Exception - Inner exceptions: {0}", e.InnerExceptions);
        logger.ErrorFormat("TaskScheduler Unobserved Exception - StackTrace: {0}", e.StackTrace);
        args.SetObserved();
    };
}

如果你想从任务本身处理它,你也可以使用类似的东西:

/// <summary>
/// Handles all the exceptions thrown by the <paramref name="task"/>
/// </summary>
/// <param name="task">The task which might throw exceptions.</param>
/// <param name="exceptionsHandler">The handler to which every exception is passed.</param>
/// <returns>The continuation task added to <paramref name="task"/>.</returns>
public static Task HandleExceptions(this Task task, Action<Exception> exceptionsHandler)
{
    return task.ContinueWith(t =>
    {
        var e = t.Exception;

        if (e == null) { return; }

        e.Flatten().Handle(ie =>
        {
            exceptionsHandler(ie);
            return true;
        });
    },
    CancellationToken.None,
    TaskContinuationOptions.ExecuteSynchronously,
    TaskScheduler.Default);
}

【讨论】:

  • 添加第一个方法,仍然没有显示异常。关于第二个代码 - 谢谢。
  • 刚刚在 LINQPad 上尝试过,您的代码会引发异常。并添加上面的方法也可以捕获它。我认为你的问题是 Console.ReadLine 阻止它被抛出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
相关资源
最近更新 更多