[英]Async-Await, exception handling and continuation using TaskContinuationOptions.OnlyOnFaulted
I have the following code for sample console application, but the method specified in Task continuation using TaskContinuationOptions.OnlyOnFaulted
never gets called. 我为示例控制台应用程序提供了以下代码,但从未调用使用
TaskContinuationOptions.OnlyOnFaulted
任务延续中指定的方法。
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);
}
}
}
}
Here, when an exception is thrown from Wait()
method, instead of HandleException(...)
being called, either program crashes or debugger shows an unhandled exception dialog box. 在这里,当从
Wait()
方法引发异常时,而不是调用HandleException(...)
,程序崩溃或调试器将显示未处理的异常对话框。
EDITED: Return type of NewTask
method is Task
. 编辑:
NewTask
方法的返回类型是Task
。
By calling Factory.StartNew
, you're actually creating a task whose method body just initiates your actual task , but your actual task has no continuation on it; 通过调用
Factory.StartNew
,您实际上是在创建一个任务,该任务的方法主体只是初始化您的实际任务 ,但是您的实际任务没有延续性; only the outer, superfluous task (which won't throw an exception) has one. 只有外部多余的任务(不会抛出异常)才有一个。
Additionally, your async function is async void
. 另外,您的异步函数是
async void
。 This makes it impossible to add a continuation. 这使得不可能添加延续。 I'm going to go one step further and say that you should never, ever, make a function that's
async void
. 我要更进一步,说您永远都不要做一个
async void
的函数 。 It should always be async Task
. 它应该始终是
async Task
。
If you make that syntax change, your calling syntax is actually simpler: 如果您更改了语法,则调用语法实际上会更简单:
NewTask(index).ContinueWith(HandleException, cts.Token,
TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
However, bear in mind that cancellation is not something that you get for free; 但是,请记住,取消并不是您免费获得的东西。 you either need to be passing your token along to other asynchronous tasks that make use of it or you need to be checking it youself (or call
.ThrowIfCancellationRequested()
). 您要么需要将令牌传递给其他使用它的异步任务,要么需要自己进行检查(或调用
.ThrowIfCancellationRequested()
)。
As an aside, by convention any function which returns a Task
or Task<T>
should have its name end with Async
(ie it should be named NewTaskAsync
). NewTaskAsync
,按照约定,任何返回Task
或Task<T>
函数的名称都应以Async
结尾(即,应将其命名为NewTaskAsync
)。
I have the following code for sample console application
我有以下示例控制台应用程序代码
I assume you're doing this to learn async
and await
. 我认为您正在这样做是为了学习
async
并await
。 Here's some tips. 这里有一些技巧。
Task.Factory.StartNew
. Task.Factory.StartNew
。 Most of the time you don't need to execute code on a background thread, but if you do, then use Task.Run
. Task.Run
。 ContinueWith
. ContinueWith
。 Use await
instead. await
。 For Console apps, just write a Main
like this: 对于控制台应用程序,只需编写如下的
Main
:
public static void Main(string[] args)
{
MainAsync().Wait();
}
And then put your real logic into a real async
method: 然后将真正的逻辑放入真正的
async
方法中:
public static async Task MainAsync()
{
...
}
You may find my async
intro helpful. 您可能会发现我的
async
介绍很有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.