如何使用 OnlyOnFaulted 选项等待任务?
How to wait on Task with OnlyOnFaulted option?
我有这个简单的 HelloTask WorldTask 控制台程序。当 HelloTask 抛出错误时,我想调用 ExceptionTask 然后通知用户程序结束。
我可以调用 ExceptionTask,但无法等待任务。我收到 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!");
}
}
您可以使用 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 语句并在调用它的地方捕获相关的异常(取消或聚合)。
您可以使用 async void
方法作为任务 "completion event" 的处理程序:
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
方法中有任何导致意外异常的错误,您将立即了解它,因为 async void
方法中的异常会导致应用程序立即崩溃。就像 UI 应用程序的事件处理程序中抛出的未处理异常一样。
How to solve this issue ? Is there a way to wait on ExceptionTask or check if a task was cancelled ?
我强烈建议将 ContinueWith
的所有实例替换为 await
:
static async Task Main(string[] args)
{
try
{
await Task.Run(() => HelloTask());
WorldTask();
}
catch
{
ExceptionTask();
}
var userMessage = "Finished processing. Press a key to end.";
Console.WriteLine(userMessage);
Console.ReadKey();
}
我有这个简单的 HelloTask WorldTask 控制台程序。当 HelloTask 抛出错误时,我想调用 ExceptionTask 然后通知用户程序结束。
我可以调用 ExceptionTask,但无法等待任务。我收到 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!");
}
}
您可以使用 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 语句并在调用它的地方捕获相关的异常(取消或聚合)。
您可以使用 async void
方法作为任务 "completion event" 的处理程序:
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
方法中有任何导致意外异常的错误,您将立即了解它,因为 async void
方法中的异常会导致应用程序立即崩溃。就像 UI 应用程序的事件处理程序中抛出的未处理异常一样。
How to solve this issue ? Is there a way to wait on ExceptionTask or check if a task was cancelled ?
我强烈建议将 ContinueWith
的所有实例替换为 await
:
static async Task Main(string[] args)
{
try
{
await Task.Run(() => HelloTask());
WorldTask();
}
catch
{
ExceptionTask();
}
var userMessage = "Finished processing. Press a key to end.";
Console.WriteLine(userMessage);
Console.ReadKey();
}