您不需要为此启动长时间运行的任务 - 只需直接使您的方法异步:
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
lambda,则应使该方法采用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);