为什么原来的任务在 ContinueWith else 时被取消了?

Why is the original task canceled when it ContinueWith something else?

我开始学习 C# 编程已经 4 周了。很好玩,但是,我的屁股很痛:

当我单独使用 HttpClient.PostAsync() 启动任务时,它工作正常。但如果我继续做其他事情,原来的任务将被取消,而不是被我取消。任务似乎对继续进行不满意。

Task<HttpResponseMessage> task0;
Task task1;

using (var client = new HttpClient())
{
    HttpContent content = new ByteArrayContent(new byte[]{});

    task0 = client.PostAsync("<valid http address>", content);

    task1 = task0.ContinueWith((t) =>
    {
         // Do nothing
    });
}

task1.Wait();

// I got task0.IsCanceled == true here

我试过了:

1,在PostAsync()后立即添加task0.wait()可以解决问题,但这不是我想要的。因为我需要从异步中获得性能优势,这样做会使它完全同步。

2、在task1.wait()前加task0.wait()会造成TaskCanceledExcpetion.

3、去掉task1等待task0即可。

4、调用task0.start()会得到"Start may not be called on a promise-style task."

所以,有人告诉我我做错了什么吗?

PS:

在我问这个问题之前,我已经用谷歌搜索了好几天。来自 Whosebug 的一些问题可能看起来相关,但事实证明它们与我的不一样。

Who canceled my Task? She/He 询问为什么没有执行延续任务。

Why does TaskCanceledException occur? She/He 弄乱了我从未做过的 CancellationToken,并得到了意想不到的结果。

我也读过这个 Task Cancellation 但仍然没有任何线索。

您的 HttpClient 很可能在 PostAsync 完成之前就已处理完毕。出于测试目的删除 using 语句,一切都会按预期工作。请求完成后,您应该在不同的时间处理您的客户。

此外,如果您的应用程序逻辑允许,许多人会建议尽可能重用 HttpClient 的单个实例。

因此,此代码似乎在您连接延续后立即处理 HttpClient,这很可能不是您想要的。

如果要使用using 语句来处理客户端实例,则需要使用asyncawait 关键字。以下代码等同于您的示例,编译器为您连接了延续。

public async Task FooAsync()
{
    using (var client = new HttpClient())
    {
        HttpContent content = new ByteArrayContent(new byte[]{});

        await client.PostAsync("<valid http address>", content);

        // Continue your code here.
    }
}

如果你想继续使用在没有编译器帮助的情况下创建的continuations,你可以将处理逻辑放在continuation中:

Task<HttpResponseMessage> task0;
Task task1;

var client = new HttpClient();

HttpContent content = new ByteArrayContent(new byte[]{});

task0 = client.PostAsync("<valid http address>", content);

task1 = task0.ContinueWith((t) =>
{
    client.Dispose();
})

task1.Wait();