C# 类型';T';这是不可期待的
我正在创建一个任务调度器,所以我试图创建某种重复函数来接受任务并等待它,但我遇到了一个奇怪的异常,即C# 类型';T';这是不可期待的,c#,task-parallel-library,task,async-await,C#,Task Parallel Library,Task,Async Await,我正在创建一个任务调度器,所以我试图创建某种重复函数来接受任务并等待它,但我遇到了一个奇怪的异常,即类型“T”不可等待 public static Task<T> Interval<T>(TimeSpan pollInterval, Func<T> action, CancellationToken token) { return Task.Factory.StartNew( async () => {
类型“T”不可等待
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);
}
公共静态任务间隔(TimeSpan pollInterval、Func action、CancellationToken)
{
return Task.Factory.StartNew(
异步()=>
{
对于(;;)
{
if(token.WaitCancellationRequested(pollInterval))
打破
等待行动();
}
},标记,TaskCreationOptions.LongRunning,TaskScheduler.Default);
}
那么,有谁能告诉我,我如何才能等待一个通用任务,因为我希望函数接受任何任务、任务、bool或任何其他类型的任务?你不能
您可以创建一个采用通用异步函数的函数–一个返回任务的函数
那将是一个Func
您还可以创建一个采用通用同步函数的函数,这就是您现在拥有的
您不能生成一个可以接受其中任何一个的函数,但可以生成两个重载
另一方面,函数从未实际使用函数的返回值。
因此,你根本不应该让它通用;相反,您应该执行Func
或操作
您不需要为此启动长时间运行的任务-只需直接使您的方法异步即可:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(true)
{
await Task.Delay(pollInterval, token);
action();
}
}
这将导致操作
在当前上下文上运行。如果不需要,您可以使用:
await Task.Delay(pollInterval, token).ConfigureAwait(false);
action();
这将导致操作
不在调用方的同一同步上下文上运行,并可能使用线程池线程
根据评论进行编辑:
如果您不希望生成的任务被取消,而只是在触发令牌时返回,则可以使用:
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;
}
}
}
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);
}
}
编辑2:
如果要传入async
lambdas,应使该方法采用Func
,而不是操作
:
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();
}
}
在这里检查一个例子。
同意SLaks,您需要使Func的泛型参数T可等待以使用等待。
例如,如果T是一个字符串
,则代码将“等待”一个只返回字符串的函数。
wait
仅对任务有效。欲了解更多信息,请查看此说明;示例在VB.net中。为什么Interval
返回任务
?它永远不会结束(直到出现异常或It错误才会结束),而且它从来没有设置为结果的T
值。@Servy no我有一个cancel Token Yes,如果它被取消,则任务被设置为cancel状态。它仍然没有结果。它在某个点上完成,但是它从来没有一个可以获取的结果。我的观点是,您应该返回一个任务,而不是任务
,并且您应该接受一个操作
,而不是函数
,因为您放弃了函数的结果。@Servy:很抱歉,我无法理解您的想法;但是如果你理解我的问题。我想要实现的是,我想要函数接受任何类型的任务,int或bool或任何类型的任务。。。这能实现吗?或者我该怎么做呢请注意,您的函数在延迟期间浪费了一个线程。您应该使用wait Task.Delay()
相反:请您通过发布代码片段来更详细地回答问题,或者更清楚地说明问题,因为我听不懂您的意思?@RuneS:您不明白哪一部分?我想清楚的是,在这个函数中,我得到了一个等待的方法,可以重复,直到我通过i cancelation token取消它为止。。。因此,假设我有一个返回值而不是空值的任务。@RuneS:awaitable函数是指返回task
,而不是T
的函数。这意味着您要编写Func
.static类CancellationTokenExtensions{public static bool WaitCancellationRequested(此CancellationToken,TimeSpan timeout){return token.WaitHandle.WaitOne(timeout);}}我可以将while(true)改为while(!token.WaitCancellationRequested)吗(pollInterval))@RuneS是阻塞的。上面是完全异步的(非阻塞)@RuneS:与Reed的代码不同,您的方法在延迟期间会浪费一个线程。Reed的代码是正确的编写方法。让我们来看看
RunAtIntervalAsync(TimeSpan.FromSeconds(1),
async () => { await Task.Delay(1000); return "Foo"; },
result => UpdateUI(result),
token);