【问题标题】:Type 'T' is not awaitable类型“T”不可等待
【发布时间】:2013-07-21 16:54:10
【问题描述】:

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

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

【问题讨论】:

  • 为什么Interval 返回Task&lt;T&gt;?它永远不会结束(它只会永远持续下去,直到出现异常或错误),并且它永远不会将T 值设置为结果。
  • @Servy 没有我有一个取消令牌
  • 是的,如果它被取消,那么任务将被设置为取消状态。它仍然没有结果。它在某个时候完成,但它从来没有您可以获取的Result。我的意思是你应该返回一个Task,而不是Task&lt;T&gt;,你应该接受Action而不是Func&lt;T&gt;,因为你丢弃了函数的结果。
  • @Servy :我很抱歉,但我不明白你的想法;但是,如果您理解我的问题。我想要实现的是我希望函数接受任何类型的 Task、int 或 bool 或任何任何类型​​......这可以实现吗?或者我怎么能绕过
  • 请注意,您的函数在延迟期间浪费了一个线程。您应该改用await Task.Delay()msdn.microsoft.com/en-us/library/hh194845.aspx

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


【解决方案1】:

你不能。

您可以创建一个采用通用异步函数的函数——一个返回Task&lt;T&gt;的函数。
那将是Func&lt;Task&lt;T&gt;&gt;

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

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


在不相关的说明中,您的函数实际上从未使用函数的返回值。
因此,您根本不应该使其通用。你应该改用Func&lt;Task&gt;Action

【讨论】:

  • 请您通过发布代码 sn-ps 使您的答案更详细,或者只是让它更清楚,因为我听不懂你吗?
  • @RuneS:你不明白哪一部分?
  • 我想要清楚地做的是,在这个函数内部,我得到一个等待的方法来重复,直到我通过取消令牌取消它......所以想象我有一个返回值的任务虚无。
  • @RuneS:可等待函数是指返回Task而不是T的函数。这意味着你想写Func&lt;Task&gt;
【解决方案2】:

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

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 线程。


编辑以响应 cmets:

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

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&lt;Task&gt;,而不是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);

【讨论】:

  • 静态类 CancellationTokenExtensions { public static bool WaitCancellationRequested(this CancellationToken token, TimeSpan timeout) { return token.WaitHandle.WaitOne(timeout); } }
  • 我可以将 while(true) 转换为 while (!token.WaitCancellationRequested(pollInterval))
  • @RuneS 不过,这会阻塞。以上是完全异步的(非阻塞)
  • @RuneS:与 Reed 的代码不同,您的方法会在延迟期间浪费一个线程。 Reed 的代码是正确的写法。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-15
    • 2019-03-04
    • 2017-12-29
    • 2019-01-31
    • 2019-11-17
    相关资源
    最近更新 更多