Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type 'T' is not awaitable

i am creating a task scheduler so i am trying to make some kind of repeating function that accepts Task and awaits it but i get a strange Exception of Type 'T' is not awaitable

public static Task<T> Interval<T>(TimeSpan pollInterval, Func<T> action, CancellationToken token)
{
    return Task.Factory.StartNew(
        async () =>
        {
            for (; ; )
            {
                if (token.WaitCancellationRequested(pollInterval))
                    break;

                await action();
            }
        }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

So can anyone tell me how could i await a that generic Task cuz i want the function to accept any Task, Task, bool or any other type ?

like image 871
Roman Ratskey Avatar asked Jul 22 '13 19:07

Roman Ratskey


2 Answers

You don't need to start a long running task for this - just make your method asynchronous directly:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
    while(true)
    {
        await Task.Delay(pollInterval, token);
        action();
    }
}

This will cause the Action to run on the current context. If that is not required, you can use:

await Task.Delay(pollInterval, token).ConfigureAwait(false);
action();

This will cause the Action to not run on the same synchronization context of the caller, and potentially use a ThreadPool thread.


Edit in response to comments:

If you don't want the resulting task to come back canceled, but just return when the token is fired, you could use:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        try
        {
            await Task.Delay(pollInterval, token);
            action();
        }
        catch(OperationCanceledException e)
        {
            // Swallow cancellation - dangerous if action() throws this, though....
            break;
        }
    }
}

Edit 2:

If you want to pass in async lambdas, you should make the method take an Func<Task>, not Action:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Func<Task> actionTask, CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        try
        {
            await Task.Delay(pollInterval, token);
        }
        catch(OperationCanceledException e)
        {
            // Swallow cancellation
            break;
        }

        await actionTask();
    }
}

Edit in response to chat:

If you want to poll, but use the results of an operation, you could use:

public static async Task RunAtIntervalAsync<T>(TimeSpan pollInterval, Func<Task<T>> fetchOperation, Action<T> operationOnResult, CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        try
        {
            await Task.Delay(pollInterval, token);
        }
        catch(OperationCanceledException e)
        {
            // Swallow cancellation
            break;
        }

        // Get a value
        T value = await fetchOperation();

        // Use result (ie: update UI)
        operationOnResult(value);
    }
}

You could then call this via:

RunAtIntervalAsync(TimeSpan.FromSeconds(1), 
   async () => { await Task.Delay(1000); return "Foo"; },
   result => UpdateUI(result),
   token);
like image 145
Reed Copsey Avatar answered Nov 13 '22 18:11

Reed Copsey


You can't.

You can make a function that takes a generic asynchronous function – a function that returns a Task<T>.
That would be a Func<Task<T>>.

You can also make a function that takes a generic synchronous function, which is what you have now.

You can't make a single function that can take either, but you can make two overloads.


On an unrelated note, your function never actually uses the return value of the function.
Therefore, you shouldn't make it generic at all; you should instead take a Func<Task> or an Action.

like image 5
SLaks Avatar answered Nov 13 '22 17:11

SLaks