21

我正在使用以下

Task.Factory.StartNew(() => DoPrintConfigPage(serial));

然后我调用的函数看起来像这样

private void DoPrintConfigPage(string serial) 
{ 
    //do printing work 
}

我的问题是在线程内抛出异常并且没有被处理。

我已经尝试将它包装在 try catch

try
{
    Task.Factory.StartNew(() => DoPrintConfigPage(serial));
}
catch (Exception ex) { }

但它仍然没有捕捉到错误,从而导致应用程序崩溃。

如何在主线程中捕获异常以便处理它们?

更新

我已经进行了下面建议的更改,但仍然说异常未处理

var task =  Task.Factory.StartNew(() => DoPrintConfigPage(serial))
                               .ContinueWith(tsk =>
                               {
                                  MessageBox.Show("something broke");
                               },TaskContinuationOptions.OnlyOnFaulted);

然后在我的DoConfigPage我添加了另一个尝试捕获。

在这个捕获中,现在它正在崩溃并说抛出的异常未处理,我错过了什么?

private void DoPrintConfigPage(string serial)
{
    try
    {
        //call the print function
    }
    catch (Exception ex)
    {
        throw ex;   //it is crashing here and saying it is unhandled
    }
}

我还尝试了 Eric J. 的建议,结果相同

var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial));

try
{
    task.Wait();                  
}
catch (AggregateException ex) { MessageBox.Show("something broke"); }
4

5 回答 5

40

或者,您可以链接您的任务创建并添加 ContinueWith:

var job = Task.Factory
    .StartNew(...)
    .ContinueWith(tsk => 
         {
              // check tsk for exception and handle
         });

编辑:这个片段在运行时会为我弹出消息框:

void Main()
{
    var serial = "some serial";
    var task =  Task.Factory
        .StartNew(() => DoPrintConfigPage(serial))
        .ContinueWith(tsk =>
        {
            MessageBox.Show("something broke");
            var flattened = tsk.Exception.Flatten();

            // NOTE: Don't actually handle exceptions this way, m'kay?
            flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true;});
        },TaskContinuationOptions.OnlyOnFaulted);

}

public void DoPrintConfigPage(string serial)
{
    throw new Exception("BOOM!");
}
于 2013-02-14T21:01:55.447 回答
11

在您开始新任务后,您的try块会立即退出,因为该方法会继续运行。

相反,您可以在等待任务(或多个任务)完成时将异常捕获为AggregateException :

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("I'm bad, but not too bad!");
});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{
    // Assume we know what's going on with this particular exception. 
    // Rethrow anything else. AggregateException.Handle provides 
    // another way to express this. See later example. 
    foreach (var e in ae.InnerExceptions)
    {
        if (e is MyCustomException)
        {
            Console.WriteLine(e.Message);
        }
        else
        {
            throw;
        }
    }

}

http://msdn.microsoft.com/en-us/library/dd997415.aspx

于 2013-02-14T20:56:04.067 回答
7

如果您不等待您的任务,我认为在Task.Exception中可以找到最简单的解决方案:

获取导致 Task 过早结束的 AggregateException。如果 Task 成功完成或尚未抛出任何异常,则返回 null。

我正在使用这样的东西:

Task.Factory.StartNew(() => DoStuffHere())
    .ContinueWith(task =>
    {
        if (task.Exception != null)
            Log("log all the exceptions!");
    });
于 2015-08-27T16:31:24.503 回答
3

您还应该了解 System.Threading.Tasks.TaskScheduler.UnobservedTaskException

如果您从事创建“即发即弃”Task实例的业务,您将希望在程序开始时订阅该事件。

于 2013-02-14T21:01:25.237 回答
0

也许您正在尝试捕获Corrupted State Exception。由于 .NET 4 应用程序默认无法捕获此类异常。您可以尝试将legacyCorruptedState­­ExceptionsPolicy=true条目添加到您的配置文件中,如上面链接的 MSDN 文章中所述。

于 2017-03-30T10:50:26.060 回答