异步等待、异常处理和使用TaskContinuationOptions.OnlyOnFaulted继续

本文关键字:TaskContinuationOptions OnlyOnFaulted 继续 等待 异常处理 异步 | 更新日期: 2023-09-27 18:00:40

我有以下示例控制台应用程序的代码,但从未调用在使用TaskContinuationOptions.OnlyOnFaulted的Task continuation中指定的方法。

using System;
using System.Threading;
using System.Threading.Tasks;
namespace Sample
{
    class Program
    {
        public static void Main(string[] args)
        {
            int index = 0;
            var cts = new CancellationTokenSource();
            Task.Factory.StartNew(() => NewTask(index), cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                .ContinueWith(HandleException, cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
            // Some code
            // ...
            Console.ReadLine();
        }
        private static async Task NewTask(int index)
        {
            Console.WriteLine(index);
            await Wait();
        }
        private static async Task Wait()
        {
            await Task.Delay(500);
            throw new Exception("Testing 123");
        }
        private static void HandleException(Task task)
        {
            if (task != null && task.Exception != null)
            {
                var exceptions = task.Exception.Flatten().InnerExceptions;
                if (exceptions != null)
                    foreach (var exception in exceptions)
                        Console.WriteLine(exception.Message);
            }
        }
    }
}

这里,当从Wait()方法引发异常时,而不是调用HandleException(...),程序崩溃或调试器显示未处理的异常对话框。

已编辑:NewTask方法的返回类型为Task

异步等待、异常处理和使用TaskContinuationOptions.OnlyOnFaulted继续

通过调用Factory.StartNew,您实际上创建了一个任务,该任务的方法体只是启动实际任务,但实际任务上没有延续;只有外部多余的任务(不会抛出异常)才有一个。

此外,您的异步函数是async void。这使得无法添加延续。我将更进一步,说永远不应该生成async void的函数。它应该始终是async Task

如果您更改了语法,那么您的调用语法实际上更简单:

NewTask(index).ContinueWith(HandleException, cts.Token, 
    TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);

然而,请记住,取消不是免费的;您要么需要将您的令牌传递给其他使用它的异步任务,要么需要自己检查它(或调用.ThrowIfCancellationRequested())。

顺便说一句,根据惯例,任何返回TaskTask<T>的函数的名称都应以Async结尾(即应命名为NewTaskAsync)。

我有以下用于示例控制台应用程序的代码

我想你这样做是为了学习asyncawait。以下是一些提示。

  • 不要使用Task.Factory.StartNew。大多数时候,不需要在后台线程上执行代码,但如果需要,请使用Task.Run
  • 不要使用ContinueWith。请改用await
  • 遵循基于任务的异步模式
  • 理解控制台应用程序是而不是异步应用程序的正常用例。如果你打算最终进入UI应用程序,那么你应该从UI应用程序开始

对于控制台应用程序,只需编写一个Main,如下所示:

public static void Main(string[] args)
{
  MainAsync().Wait();
}

然后把你真正的逻辑放到一个真正的async方法中:

public static async Task MainAsync()
{
  ...
}

你可能会发现我的async简介很有帮助。

相关文章:
  • 没有找到相关文章