6

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

所以谁能告诉我我怎么能等待一个通用的任务因为我希望函数接受任何任务、任务、布尔或任何其他类型?

4

3 回答 3

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:

如果要传入asynclambda,则应使该方法采用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);
于 2013-07-22T20:08:14.663 回答
5

你不能。

您可以创建一个采用通用异步函数的函数——一个返回Task<T>.
那将是一个Func<Task<T>>.

您还可以创建一个采用通用同步函数的函数,这就是您现在所拥有的。

你不能创建一个可以接受任何一个的函数,但你可以创建两个重载。


在不相关的说明中,您的函数实际上从未使用函数的返回值。
因此,您根本不应该使其通用。您应该改为使用 aFunc<Task>Action.

于 2013-07-22T20:00:21.813 回答
0

在此处查看示例post。同意SLaks,您需要使 Func 的泛型参数 T 可等待才能使用等待。例如,如果 T 是 a string,则代码将“等待”一个只返回 a 的函数stringawait仅对任务有效。有关更多信息,请查看此说明MSDN 博客;该示例在 VB.net 中。

于 2013-07-22T20:51:02.440 回答