0

下面是一些在 LinqPad 中“按原样”运行的代码。它表明我对await正在做的事情的误解。进一步查看结果和我的问题。

    void Main()
{
    var cts = new CancellationTokenSource();
    StartIt(cts.Token);
    Thread.Sleep(500);
    "Cancelling".Dump();
    cts.Cancel();
}


// Define other methods and classes here
async Task StartIt(CancellationToken token)
{
    "StartIt".Dump();
    var o = new TestClass();

    await o.Step0(token);

}

public class TestClass
{
    public async Task Step0(CancellationToken token)
    {
        var t = Step1(token);
        ("Step0.Task.Id => " + t.Id).Dump();        

        await t;
        ("Step0.IsCancelled? " + t.IsCanceled).Dump();
    }

    public async Task Step1(CancellationToken token)
    {
        var t = Step2(token);
        ("Step1.Task.Id => " + t.Id).Dump();

        try {
            await t;
        }
        catch (OperationCanceledException)
        {
            "Step1.OperationCanceledException".Dump();
        }
        ("Step1.IsCancelled? " + t.IsCanceled).Dump();
    }

    public Task Step2(CancellationToken token)
    {
        return Task.Run(() =>{
                Thread.Sleep(3000);
                token.ThrowIfCancellationRequested();
                "Done".Dump();
            }, token);
    }
}

所以上面产生:

StartIt
Step1.Task.Id => 17
Step0.Task.Id => 18
Cancelling
Step1.OperationCanceledException
Step1.IsCancelled? True
Step0.IsCancelled? False

我的问题:

我希望 Step0 和 Step1 的 task.Id 相同。(因此)我希望发生的取消能够传播方法,以便我可以询问t.IsCanceled并采取适当的措施。

但我得到了一个不同Task的返回Step0。我错过了什么?

谢谢

4

1 回答 1

3

我建议您阅读我async. 此外,LinqPad 内置了一个出色的教程(示例 -> 下载/导入更多示例 -> C# 5 交互式教程中的异步)。

代码中的任务标识符async可能有点棘手。发生的情况是每个async Task方法都会创建自己的任务来表示该方法调用。因此,Task.Run创建 aTask并将其返回给Step2and Step1(测试中的 id 17)。Step1还创建 aTask并将其返回到Step0(测试中的 id 18)。Step0还创建 aTask并将其返回给StartItStartIt还创建 aTask并将其返回给Main

因此,Task返回的Task.Run(与Task返回的相同Step2)被取消。Step1捕捉到被取消的异常,所以正常返回,Task返回的由Step1不被取消。

如果您想传播异常,请不要捕获已取消的异常(或者如果您确实想捕获它以记录,然后通过 重新抛出它throw;)。

于 2013-09-11T16:38:50.730 回答