このために長時間実行されるタスクを開始する必要はありません。メソッドを直接非同期にするだけです。
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
、メソッドが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);