Обнаружение отмены связанного токена в C #? - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь обеспечить эту семантику для отменяемого фрагмента кода в случае OperationCancelledException:

  1. Если вызывающая сторона является причиной, уважайте ее и (повторно) бросьте

  2. Если мы или какой-либо нижестоящий код является причиной, переведите это на «недоступный» ответ

К сожалению, вторая часть проблематична.

Если нижестоящий код связывает источник, а затем отменяет + throws, я не могу его обнаружить. Я ожидаю, что мой собственный источник вызовет IsCancellationRequested, но это не так.

Вот некоторый код, иллюстрирующий проблему

    public void TestDownstreamCancellation()
    {
        var cancellationToken = new CancellationTokenSource().Token;
        var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        try
        {
            var inner = CancellationTokenSource.CreateLinkedTokenSource(cts.Token);
            inner.Cancel();
            inner.Token.ThrowIfCancellationRequested();
        }
        catch (OperationCanceledException e)
        {
            // All right - we may be seeing this because we have cancelled the internal tasks (they execute
            // cancellationToken.ThrowIfCancellationRequested(), which is a rational way to bail out).
            // But it could also be because the outer (caller owned) token cancelled, in which case we should re-throw.
            if (e.CancellationToken == cancellationToken)
            {
                // The cause of the exception is that the caller of the composite requested termination, re-throwing!
                // Case is separated out for clatiry and (possibly) logging purposes.
                throw;
            }
            else if (cts.Token.IsCancellationRequested)
            {
                // Check if the cause is actually the passed-in token. If so, we should not translate this exception to a
                // ServiceUnavailable response. May be redundant, as the previous if branch should have caught this
                cancellationToken.ThrowIfCancellationRequested();

                // The cause of the exception is that one of the sub-tasks responded to a cancellation request by throwing
                // OperationCanceled. We translate this to ServiceUnavailable. It's always iffy to rely on exception behavior for control
                // flow, but in this case it's quite well-defined what's going on, as it's very common for an async task to honor a
                // cancellation request by throwing this exception.

                // return ServiceUnavailable;
            }
            else
            {
                // Something else threw, so raise it again and let the caller deal with it.
                throw;
            }
        }

Я бы ожидал 2-го. срабатывающая ветвь, но это не так - вместо этого мы ударяем 3-ю ветвь и перебрасываем.

...