Task.Run和Task.Factory.StartNew之间的异常处理

Def*_*ult 13 c# exception task-parallel-library taskfactory

我在使用时遇到了一个问题,Task.Factory.StartNew并试图捕获exception被抛出的问题.在我的应用程序中,我有一个长期运行的任务,我想封装在一个Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);

但是,当我使用时,没有捕获异常Task.Factory.StartNew.然而,当我使用时Task.Run,它正如我所期望的那样工作,我认为它只是一个包装器Task.Factory.StartNew(根据例如这篇MSDN文章).

这里提供了一个工作示例,不同之处在于在使用时将异常写入控制台Task.Run,但在使用时不会Factory.StartNew.

我的问题是:
如果我有一个LongRunning可以抛出异常的任务,我应该如何在调用代码中处理它们?

private static void Main(string[] args)
{
    Task<bool> t = RunLongTask();
    t.Wait();
    Console.WriteLine(t.Result);
    Console.ReadKey();
}

private async static Task<bool> RunLongTask()
{
    try
    {
        await RunTaskAsync();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        return false;
    }
    Console.WriteLine("success");
    return true;
}

private static Task RunTaskAsync()
{
    //return Task.Run(async () =>
    //    {
    //        throw new Exception("my exception");
    //    });
    return Task.Factory.StartNew(
        async () =>
    {
        throw new Exception("my exception");
    });

}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 16

你的问题是与代表StartNew不一样.返回类型是(可转换为)."outer" 表示方法的开头,"inner" 表示方法的完成(包括任何例外).Task.RunasyncStartNewTask<Task>TaskTaskTask

要进入内心Task,你可以使用Unwrap.或者你也可以使用Task.Run,而不是StartNewasync代码.LongRunning只是一个优化提示,实际上是可选的.斯蒂芬Toub对之间的区别了良好的博客文章StartNewRun为什么Run(通常)更好的async代码.

从以下@usr评论更新: LongRunning仅适用于async方法的开头(直到第一个未完成的操作被await编辑).所以Task.Run在这种情况下使用它几乎肯定更好.