类型'T'不等待

时间:2013-07-22 19:58:27

标签: c# task-parallel-library task async-await

我正在创建一个任务调度程序,所以我试图创建某种重复函数,接受任务并等待它但我得到一个奇怪的例外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);
}

所以有人可以告诉我,我怎么能等待那个通用任务因为我希望函数接受任何Task,Task,bool或任何其他类型?

3 个答案:

答案 0 :(得分:8)

您不需要为此启动长时间运行的任务 - 只需使您的方法直接异步:

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

这将导致Action在当前上下文中运行。如果不需要,您可以使用:

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

这将导致Action无法在调用者的同一同步上下文中运行,并可能使用ThreadPool线程。


编辑以回应评论:

如果您不希望结果任务取消,但只是在激活令牌时返回,您可以使用:

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

编辑2:

如果你想传递async lambdas,你应该让方法采用Func<Task>,而不是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();
    }
}

编辑以回应聊天:

如果您想轮询,但使用操作的结果,您可以使用:

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

然后您可以通过以下方式调用此方法:

RunAtIntervalAsync(TimeSpan.FromSeconds(1), 
   async () => { await Task.Delay(1000); return "Foo"; },
   result => UpdateUI(result),
   token);

答案 1 :(得分:5)

你不能。

你可以创建一个带有泛型异步功能的函数 - 一个返回Task<T>的函数。
那将是Func<Task<T>>

您还可以创建一个具有通用同步功能的功能,这就是您现在拥有的功能。

您不能创建一个可以执行任何操作的函数,但是您可以进行两次重载。


在不相关的注释中,您的函数实际上从未使用函数的返回值 因此,你根本不应该把它变成通用的;您应该选择Func<Task>Action

答案 2 :(得分:0)

在此处查看示例post。 同意 SLaks ,您需要使用Func的通用参数T才能使用await。 例如,如果T是string,则代码将“等待”仅返回string的函数。 await仅对任务有效。有关详细信息,请查看此解释MSDN Blog;这个例子是在VB.net中。