O operador de espera não está esperando como eu esperava

Estou trabalhando em uma aulaDelayedExecutor que atrasará a execução de umAction passou para o seuDelayExecute método por um certo tempotimeout (veja o código abaixo) usando as instruções assíncronas e aguardar. Eu também quero poder abortar a execução dentro dotimeout intervalo, se necessário. Eu escrevi um pequeno teste para testar seu comportamento assim:

Código paraMétodo de teste:

    [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);
    }
}

A saída que eu esperava deste teste foi que ele me mostraria:

sw.ElapsedMilliseconds fora de DelayExecute 1: ...

Ação Ran! "

sw.ElapsedMilliseconds dentro de DelayExecute: ...

sw.ElapsedMilliseconds fora do DelayExecute 2:

No entanto, eu entendo isso e não entendo o porquê:

sw.ElapsedMilliseconds fora de DelayExecute 1: 0

sw.ElapsedMilliseconds fora do atrasoExecute 2: 30

Ran Action!

sw.ElapsedMilliseconds dentro de DelayExecute: 1015

Nistopublicação no blog Eu li:

Eu gosto de pensar em "aguardar" como uma "espera assíncrona". Ou seja, o método assíncrono faz uma pausa até que o esperado seja concluído (o que aguarda), mas o encadeamento real não é bloqueado (portanto, é assíncrono).

Isso parece estar alinhado com a minha expectativa, então o que está acontecendo aqui e onde está o meu erro?

Código paraDelayedExecutor:

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);
            });
    }
}

Atualizar:

Conforme sugerido, modifiquei esta linha dentro do meuDelayExecute

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

para dentro

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

Para que isso funcionasse, eu precisava alterar a assinatura para este

public async Task<Task> DelayExecute(Action func)

para que minha nova definição seja esta:

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);
        });
}

No entanto, agora eu tenho o mesmo comportamento de antes. Existe alguma maneira de conseguir o que estou tentando fazer usando meu design. Ou é fundamentalmente falho?

A propósito, eu também tentei colocarawait await delayTask; dentro do meu testeDelayExecuteTest, mas isso me dá o erro

Não é possível aguardar 'nulo'

Este é o método de teste atualizadoDelayExecuteTest, qualnão compilar:

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);
}

questionAnswers(2)

yourAnswerToTheQuestion