Оператор ожидания не ждет, как я ожидал

Я работаю на урокеDelayedExecutor что задержит выполнениеAction перешел к егоDelayExecute метод к определенному времениtimeout (см. код ниже) с помощью операторов async и await. Я также хочу иметь возможность прервать выполнение в пределахtimeout интервал, если это необходимо. Я написал небольшой тест, чтобы проверить его поведение следующим образом:

Код дляМетод испытания:

    [TestMethod]
    public async Task DelayExecuteTest()
    {
        int timeout = 1000;
        var delayExecutor = new DelayedExecutor(timeout);
        Action func = new Action(() => Debug.WriteLine("Ran function!"));
        var sw = Stopwatch.StartNew();
        Debug.WriteLine("sw.ElapsedMilliseconds 1: " + sw.ElapsedMilliseconds);
        Task delayTask = delayExecutor.DelayExecute(func);
        await delayTask;
        Debug.WriteLine("sw.ElapsedMilliseconds 2: " + sw.ElapsedMilliseconds);
        Thread.Sleep(1000);
    }
}

Результат, который я ожидал от этого теста, был следующим:

sw.ElapsedMilliseconds за пределами DelayExecute 1: ...

Ран Действие! "

sw.ElapsedMilliseconds внутри DelayExecute: ...

sw.ElapsedMilliseconds за пределами DelayExecute 2:

Однако я понимаю это и не понимаю, почему:

sw.ElapsedMilliseconds за пределами DelayExecute 1: 0

sw.ElapsedMilliseconds за пределами DelayExecute 2: 30

Ран Действие!

sw.ElapsedMilliseconds внутри DelayExecute: 1015

На этомСообщение блога Я читаю:

Мне нравится думать об «ожидании» как «асинхронном ожидании». То есть асинхронный метод приостанавливается до тех пор, пока ожидаемое не будет завершено (поэтому он ожидает), но реальный поток не блокируется (поэтому он асинхронный).

Кажется, это соответствует моим ожиданиям, так что здесь происходит и где моя ошибка?

Код дляDelayedExecutor:

public class DelayedExecutor
{
    private int timeout;

    private Task currentTask;
    private CancellationToken cancellationToken;
    private CancellationTokenSource tokenSource;

    public DelayedExecutor(int timeout)
    {
        this.timeout = timeout;
        tokenSource = new CancellationTokenSource();
    }

    public void AbortCurrentTask()
    {
        if (currentTask != null)
        {
            if (!currentTask.IsCompleted)
            {
                tokenSource.Cancel();
            }
        }
    }

    public Task DelayExecute(Action func)
    {
        AbortCurrentTask();

        tokenSource = new CancellationTokenSource();
        cancellationToken = tokenSource.Token;

        return currentTask = Task.Factory.StartNew(async () =>
            {
                var sw = Stopwatch.StartNew();
                await Task.Delay(timeout, cancellationToken);
                func();
                Debug.WriteLine("sw.ElapsedMilliseconds inside DelayExecute: " + sw.ElapsedMilliseconds);
            });
    }
}

Обновить:

Как и предполагалось, я изменил эту строку внутри моегоDelayExecute

return currentTask = Task.Factory.StartNew(async () =>

в

return currentTask = await Task.Factory.StartNew(async () =>

Чтобы это работало, мне нужно было поменять подпись на эту

public async Task<Task> DelayExecute(Action func)

так что мое новое определение таково:

public async Task<Task> DelayExecute(Action func)
{
    AbortCurrentTask();

    tokenSource = new CancellationTokenSource();
    cancellationToken = tokenSource.Token;

    return currentTask = await Task.Factory.StartNew(async () =>
        {
            var sw = Stopwatch.StartNew();
            await Task.Delay(timeout, cancellationToken);
            func();
            Debug.WriteLine("sw.ElapsedMilliseconds inside DelayExecute: " + sw.ElapsedMilliseconds);
        });
}

Однако сейчас у меня такое же поведение, как и раньше. Есть ли способ достичь того, что я пытаюсь сделать, используя мой дизайн. Или это в корне ошибочно?

Кстати я тоже пробовал ставитьawait await delayTask; внутри моего тестаDelayExecuteTest, но это дает мне ошибку

Не могу дождаться "пустоты"

Это обновленный тест-методDelayExecuteTest, которыйне компиляции:

public async Task DelayExecuteTest()
{
    int timeout = 1000;
    var delayExecutor = new DelayedExecutor(timeout);
    Action func = new Action(() => Debug.WriteLine("Ran Action!"));
    var sw = Stopwatch.StartNew();
    Debug.WriteLine("sw.ElapsedMilliseconds outside DelayExecute 1: " + sw.ElapsedMilliseconds);
    Task delayTask = delayExecutor.DelayExecute(func);
    await await delayTask;
    Debug.WriteLine("sw.ElapsedMilliseconds outside DelayExecute 2: " + sw.ElapsedMilliseconds);
    Thread.Sleep(1000);
}

Ответы на вопрос(2)

Ваш ответ на вопрос