gpt4 book ai didi

c# - 为什么在使用 async await 时抛出 UnobservedTaskException?

转载 作者:太空狗 更新时间:2023-10-30 00:47:59 35 4
gpt4 key购买 nike

以下场景在 .NET 4.5 下运行,因此任何 UnobservedTaskException 都不会 terminate the process .

我习惯于在我的应用程序启动时监听任何 UnobservedTaskException 抛出的异常:

private void WatchForUnobservedTaskExceptions()
{
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
args.Exception.Dump("Ooops");
};
}

当我想显式忽略我的任务抛出的任何异常时,我还有一个辅助方法:

public static Task IgnoreExceptions(Task task) 
=> task.ContinueWith(t =>
{
var ignored = t.Exception.Dump("Checked");
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);

所以如果我执行以下代码:

void Main()
{
WatchForUnobservedTaskExceptions();

var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
throw new InvalidOperationException();
});

IgnoreExceptions(task);

GC.Collect(2);
GC.WaitForPendingFinalizers();

Console.ReadLine();
}

Console.ReadLine() 返回后,我们不会看到任何 UnobservedTaskException 抛出,这正是我们所期望的。

但是,如果我将上面的 task 更改为开始使用 async/await,其他一切都与以前相同:

var task = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
throw new InvalidOperationException();
});

现在我们得到了 UnobservedTaskException 抛出。调试代码显示继续执行时 t.Exceptionnull

如何在两种情况下正确忽略异常?

最佳答案

要么使用

var task = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
throw new InvalidOperationException();
}).Unwrap();

var task = Task.Run(async () =>
{
await Task.Delay(1000);
throw new InvalidOperationException();
});

参见 this blogpost about Task.Run vs Task.Factory.StartNew关于使用带有异步修饰符的 Task.Factory.StartNew

By using the async keyword here, the compiler is going to map this delegate to be a Func<Task<int>>: invoking the delegate will return the Task<int> to represent the eventual completion of this call. And since the delegate is Func<Task<int>>, TResult is Task<int>, and thus the type of ‘t’ is going to be Task<Task<int>>, not Task<int>.

To handle these kinds of cases, in .NET 4 we introduced the Unwrap method.

更多 background

Why Not to Use Task.Factory.StartNew?

.. Does not understand async delegates. … . The problem is that when you pass an async delegate to StartNew, it’s natural to assume that the returned task represents that delegate. However, since StartNew does not understand async delegates, what that task actually represents is just the beginning of that delegate. This is one of the first pitfalls that coders encounter when using StartNew in async code.

编辑

task 的类型在var task = Task.Factory.StartNew(async (...)) => 实际上是 Task<Task<int>> .你必须 Unwrap获取源任务。考虑到这一点:

您只能调用UnwrapTask<Task>> 上所以你可以给 IgnoreExceptions 添加一个重载以适应:

void Main()
{
WatchForUnobservedTaskExceptions();

var task = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
throw new InvalidOperationException();
});

IgnoreExceptions(task);

GC.Collect(2);
GC.WaitForPendingFinalizers();

Console.ReadLine();
}

private void WatchForUnobservedTaskExceptions()
{
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
args.Exception.Dump("Ooops");
};
}

public static Task IgnoreExceptions(Task task)
=> task.ContinueWith(t =>
{
var ignored = t.Exception.Dump("Checked");
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);


public static Task IgnoreExceptions(Task<Task> task)
=> task.Unwrap().ContinueWith(t =>
{
var ignored = t.Exception.Dump("Checked");
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);

关于c# - 为什么在使用 async await 时抛出 UnobservedTaskException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51400530/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com