如何使用OnlyOnFaulted选项等待任务?

问题描述 投票:0回答:2

我有这个简单的HelloTask WorldTask控制台程序。当HelloTask抛出错误时,我想调用ExceptionTask,然后通知用户该程序结束。

我可以调用ExceptionTask,但是我无法等待Task。我收到TaskCanceledException或在ExceptionTask完成之前打印了用户消息。

如何解决此问题?是否可以等待ExceptionTask或检查任务是否已取消?

 class Program
    {
        static void Main(string[] args)
        {
            Task helloTask = Task.Run(() => HelloTask());

            var worldTask = helloTask.ContinueWith((prevTask) => WorldTask(), 
                    TaskContinuationOptions.OnlyOnRanToCompletion);

            var exceptionTask = helloTask.ContinueWith((prevTask) => ExceptionTask(), 
                    TaskContinuationOptions.OnlyOnFaulted);

            // When no error: AggregationException is thrown 
            // with message "TaskCanceledException: A task was canceled.".
            // exceptionTask.Wait(); 

            // When error: AggregationException is thrown 
            // with message "TaskCanceledException: A task was canceled."
            // worldTask.Wait();

            // When error: After worldTask is cancelled user message is called, 
            // but that is before exceptionTask is finished !
            //Task.WaitAny(worldTask, exceptionTask); 

            var userMessage = "Finished processing. Press a key to end.";
            Console.WriteLine(userMessage);
            Console.ReadKey();
        }

        static void HelloTask()
        {
            Thread.Sleep(1000);
            // Intentional error.
            var x = 0;
            var y = 1 / x;
            Console.WriteLine("Hello");
        }

        static void WorldTask()
        {
            Thread.Sleep(1000);
            Console.WriteLine("World");
        }

        static void ExceptionTask()
        {
            Thread.Sleep(1000);
            Console.WriteLine("Exception happened!");
        }
}
c# task-parallel-library
2个回答
1
投票

您可以使用TaskContinuationOptions.AttachedToParent,然后等待原始任务。

例如:

        Task helloTask = Task.Run(() => HelloTask());

        var worldTask = helloTask.ContinueWith((prevTask) => WorldTask(), 
                TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);

        var exceptionTask = helloTask.ContinueWith((prevTask) => ExceptionTask(), 
                TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);

        await helloTask;  

视需要而定,取决于您是否要等待worldTask。

然后使用try catch语句并在您调用它的地方捕获相关异常(取消或聚合)。


0
投票

您可以使用async void方法作为任务“完成事件”的处理程序:

async void

相比于使用Task helloTask = Task.Run(() => Hello()); OnHelloCompletion(); async void OnHelloCompletion() { try { await helloTask; Console.WriteLine("Hello completed successfully"); } catch (Exception ex) { Console.WriteLine($"Hello failed, {ex}"); Environment.Exit(1); } } 方法的优势在于代码的表现力得到了提高,并且没有创建即弃即用ContinueWith的事实。如果Task方法内部有任何错误导致意外的异常,您将立即了解它,因为OnHelloCompletion方法内部的异常会导致应用程序立即崩溃。就像UI应用程序的事件处理程序中引发的未处理异常一样。

© www.soinside.com 2019 - 2024. All rights reserved.