Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用TPL处理异常_C#_Task Parallel Library - Fatal编程技术网

C# 用TPL处理异常

C# 用TPL处理异常,c#,task-parallel-library,C#,Task Parallel Library,使用TPL/Tasks,我可以使用内部try/catch语句执行异常处理: Task.Factory.StartNew( ()=> { try { // Do stuff } catch { // Handle exception } }); 或者使用ContinueWith,如下所示: Task.Factory.St

使用TPL/Tasks,我可以使用内部try/catch语句执行异常处理:

  Task.Factory.StartNew(
    ()=>
      {
        try
        {
          // Do stuff
        }
        catch
        {
          // Handle exception
        }
      });
或者使用ContinueWith,如下所示:

Task.Factory.StartNew(
    ()=>
      {
          // Do stuff
      }).ContinueWith(
        task =>
        {
          if(task.Exception != null)
            // Handle exception
        });
建议使用哪种方法?
每种方法的优缺点是什么?

在某种程度上,这是一个偏好的问题,特别是如果您“拥有”任务代码和调用代码。这里有一些要考虑的事情。< /P> 首先,你应该。无论您是通过继续操作还是在操作中使用try/catch来处理它们,这都适用

另请注意有关未捕获异常的信息。从“纯粹主义”方法(在未捕获的任务异常情况下中断流程)到不那么严厉的方法,这种改变是有效的。然而,故意依赖这种新的行为是不好的

对于两个选项中的哪一个,选择第二个选项有一个论据:在延续中处理异常。在.NET中,返回任务的方法将越来越常见。例如要正确使用这些方法,您需要一个延续(传统的方法,或者使用带有新的
await
功能的try/catch块,这相当于一件事,但更易于编码和读取)。因此,最好养成这样的习惯:假设任何
任务
都可能失败,除非您明确知道其他情况,并编写适当的异常处理行为

如果您感兴趣,这里有一种在.NET4.5中编写第二个示例的替代方法

async Task MyMethod()
{
    try
    {
        await Task.Run(
            () =>
            {
                // Some work.
            });
    }
    catch (SomeException ex)
    {
    }
}
另一个差异最常见于Windows窗体或WPF应用程序中,在这些应用程序中,您的代码是从UI线程调用的。这里,当使用
wait
时,TPL的默认行为是使用同步上下文运行continuations,该上下文将continuations封送回UI线程。也就是说,如果您的
任务.Run
是从UI线程调用的,则延续也将在UI线程上运行


如果要向用户显示对话框以响应异常,此选项非常有用。您将无法在
任务
worload中成功执行此操作。当使用显式continuations而不是
wait
时,必须将使用创建的
TaskScheduler
传递到相应的重载。

我认为这取决于上下文。如前所述,您应该只处理您知道如何处理的异常。我想说,如果你知道如何处理异常,你应该处理它

例如,如果您有一个任务,该任务应该从文件中加载一些数据,或者返回到某个默认值(这可能引发异常),一种方法是(伪代码)


对于
文件.Open
,我们知道如何继续。对于
GetFallBackValue()
我们没有,因此我们将其传播给调用方,说明我们处于不一致的状态。

您的两个示例在概念上是不同的

第一个在执行任务的内部处理异常。捕获后运行的任何代码仍将被执行

第二个调度程序调度另一个异步任务,该任务将始终在第一个任务完成后由调度程序运行

我猜答案是,这完全取决于你想要实现什么——没有明确的答案——但第二个答案更符合tpl


另外,在第二个示例中,task.IsFaulted比task.Exception更清楚,这主要取决于您的设计需要什么。需要考虑的一些事项:

捕获抛出异常的任务中的异常

  • 当任务表示某个不可分割的工作单元时,包括在特定异常类型之后进行清理
  • 当特定异常类型由于某种原因不应传播到任务之外时,例如,它需要包装在不同类型的外部异常中,以满足客户机代码对合同的期望
处理延续中的异常

  • 当异常清理应由不同的
    任务调度器调度时,例如,在线程池上运行“主”任务,但将所有异常日志整理到UI线程上
  • 如果有多个连续体有意义的话,每个连续体都会做不同的事情,但有例外,尽管这有点不寻常
  • 确保观察并适当处理未提供代码的
    任务的异常情况,例如,在
    TaskFactory.FromAsync创建任务后正确清理。尽管这取决于具体情况,但也可以通过等待
    任务来完成

如果您能够在任务本身抛出的方法中正确处理异常,您应该在第一个任务中捕获异常,而不是在继续中捕获异常,除非您有令人信服的理由不这样做。在与任务本身相同的范围内创建延续(如第二个示例中所做的)是不必要的添加更多工作

当从与定义任务的范围完全不同的范围处理异常时,在continuations中处理异常是有用的或必要的。例如,如果您有一个方法被赋予了某个任意任务,而它不知道该任务的定义可能是什么,但它需要在代码引发异常的情况下执行某些操作,那么您需要有一个处理该异常的延续


请注意,如果要使用处理异常的延续,可以使用
TaskContinuationOptions。OnlyOnFaulted
仅在任务引发异常时运行延续,而不是在延续的定义内执行检查。

感谢您提供的信息,但这与我的问题有什么关系?你的问题是“哪一个更值得推荐”,我说“这取决于上下文”,并用一个例子进行了解释。W
Task.Factory.StartNew(()=>
{
    MyObject objectToSet = null;
    try
    {
        objectToSet = File.Open("mydata");
    }
    catch (FileException ex)
    {
        // this will catch the FileException because we know how to handle that!

        // the following will however throw an exception that we cannot handle
        objectToSet = GetFallBackValue(); 
    }
    // when we are here we promise that the objectToSet is valid.
});