为什么在未取消令牌时注册委托会触发?

Why does registered delegate fire when token not canceled?

我正在尝试了解如何使用 CancellationTokens 并监听它们。我找到了说明如何注册侦听器的示例,但即使未取消进程,它仍然会触发。

我的调用测试方法:

    private static void TestRun2()
    {
        var cts = new CancellationTokenSource();  
        try
        {
            var options = new ParallelOptions
            {
                CancellationToken = cts.Token,
            };

            Parallel.Invoke(options,
                () => TestMethod(cts.Token));

            cts.Cancel();
            cts.Dispose();

        }
        catch (OperationCanceledException ex)
        {
            cts.Cancel();
            cts.Dispose();
            Console.WriteLine("Timeout");
        }
    }

注册了 CancellationToken 的相关方法:

    private static void TestMethod(CancellationToken token)
    {
        var wc = new WebClient();
        wc.DownloadStringCompleted += (s, e) => Console.WriteLine("GetWebData: Request completed.");

        // Cancellation on the token will
        // call CancelAsync on the WebClient.
        token.Register(() =>
        {
            wc.CancelAsync();
            Console.WriteLine("GetWebData: Request cancelled!");
        });

        Console.WriteLine("GetWebData: Starting request.");
        wc.DownloadStringAsync(new Uri("http://www.microsoft.com"));
    }

当我强制取消时它似乎工作...但是当我不这样做时,委托仍然被调用并且我在控制台上收到关于请求被取消的通知。我环顾四周,但没有看到任何关于为什么我会不断看到这种情况发生的解释。

所以问题是为什么它在未取消的情况下显示请求已取消?

我们来看看这个:

Parallel.Invoke(options,
    () => TestMethod(cts.Token));

cts.Cancel();
cts.Dispose();

你开火 TestMethod。 TestMethod 是异步的。它将 return 立即 。然后紧接着,您通过调用 cts.Cancel().

发出取消信号

它按设计工作。将您的回调更改为:

wc.DownloadStringCompleted += (s, e) =>
    Console.WriteLine($"GetWebData: Request completed. Cancelled: {e.Cancelled}");

它将输出:

GetWebData: Request completed. Cancelled: True

为了更好地说明我的观点,请尝试这样做:

Parallel.Invoke(options,
    () => TestMethod(cts.Token));

Thread.Sleep(5000);

cts.Cancel();
cts.Dispose();

显然,您不应该在最终实现中这样做,它只是为了演示目的。