gpt4 book ai didi

c# - 为什么抛出 TaskCanceledException 并不总是闯入调试器

转载 作者:太空狗 更新时间:2023-10-30 00:07:21 26 4
gpt4 key购买 nike

我正在深入研究 async-await 机制并观察到抛出一个我还无法解释的 TaskCanceledException

在下面的示例中(独立的)我有声明

await Task.Run(() => null);

我知道这个声明本身是无用的,但我将问题隔离开来,真正的代码有逻辑并且在某些情况下返回 null。

为什么会抛出 TaskCanceledException?如果我返回一个任意数字(在下面的示例中为 5),它不会抛出。

此外,如果我 await VS 的调试器会中断该方法,但如果我不 await 它,则只会将一条消息写入 VS 的输出窗口。

internal class Program
{
private static void Main(string[] args)
{
var testAsync = new TestAsync();

// Exception thrown but the debugger does not step in. Only a message is logged to the output window
testAsync.TestAsyncExceptionOnlyInTheOutputWindow();

// Exception thrown and the debugger breaks
testAsync.TestAsyncExceptionBreaksIntoTheDebugger();

Console.ReadKey();
}
}

internal class TestAsync
{
public async void TestAsyncExceptionOnlyInTheOutputWindow()
{
TestNullCase();
}

public async void TestAsyncExceptionBreaksIntoTheDebugger()
{
await TestNullCase();
}

private static async Task TestNullCase()
{
// This does not throw a TaskCanceledException
await Task.Run(() => 5);

// This does throw a TaskCanceledException
await Task.Run(() => null);
}
}

最佳答案

任务取消异常

原因Task.Run(() => null)返回一个被取消的任务停留在重载决议。编译器选择 static Task Run(Func<Task> function)而不是 static Task<TResult> Run<TResult>(Func<TResult> function)正如人们所料。它的作用就好像您正在调用 async代表,在这种情况下你不是。结果是 Task.Run “展开”您的返回值( null )作为一项任务,这反过来又会取消该任务。

负责的具体代码在 ProcessInnerTask private method in the UnwrapPromise<TResult> (inherits from Task<TResult> ) class 中:

private void ProcessInnerTask(Task task)
{
// If the inner task is null, the proxy should be canceled.
if (task == null)
{
TrySetCanceled(default(CancellationToken));
_state = STATE_DONE; // ... and record that we are done
}

// ...
}

您可以通过告诉编译器您不返回 Task 来轻松地告诉编译器不要这样做。 :

var result = await Task.Run(() => (object)null); // Will not throw an exception. result will be null

异常处理

这两种方法的区别在于在TestAsyncExceptionOnlyInTheOutputWindow你不await错误的任务,因此永远不会重新抛出存储在任务中的异常。

您可以通过在设置中检查 Common Language Runtime Exceptions 上的 thrown 列(Debug => Exceptions)来使调试器在这两种方法中中断:

Exceptions

关于c# - 为什么抛出 TaskCanceledException 并不总是闯入调试器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26577519/

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