Refresh という名前の非同期操作があります。最初の更新が完了する前に 2 回目の更新呼び出しが行われた場合は、それをキューに入れる必要があります。これは私が持っているものです:
public async Task Refresh(RefreshArgs refreshArgs)
{
await EnqueueRefreshTask(refreshArgs);
}
private Queue<RefreshArgs> refreshQueue =
new Queue<RefreshArgs>();
private async Task EnqueueRefreshTask(RefreshArgs refreshArgs)
{
refreshQueue.Enqueue(refreshArgs);
await ProcessRefreshQueue();
}
private Task currentRefreshTask = null;
private async Task ProcessRefreshQueue()
{
if ((currentRefreshTask == null) || (currentRefreshTask.IsCompleted))
{
if (refreshQueue.Count > 0)
{
var refreshArgs = refreshQueue.Dequeue();
currentRefreshTask = DoRefresh(refreshArgs);
await currentRefreshTask;
await ProcessRefreshQueue();
}
}
}
private async Task DoRefresh(RefreshArgs refreshArgs)
{
// Lots of code here, including calls to a server that are executed with await.
// Code outside my control may make another Refresh(args) call while this one is still processing.
// I need this one to finish before processing the next.
}
動作しますが、Tasks でこれを行うのが最善の方法かどうかはわかりません。何かご意見は?
アップデート:
私はActionBlockを使用してみました:
public async Task Refresh(RefreshArgs refreshArgs)
{
if (refreshActionBlock == null)
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions();
executionDataflowBlockOptions.MaxMessagesPerTask = 1;
executionDataflowBlockOptions.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
refreshActionBlock = new ActionBlock<RefreshArgs>(args => DoRefresh(args), executionDataflowBlockOptions);
}
await refreshActionBlock.SendAsync(refreshArgs);
}
これにより、DoRefresh がキューに入れられ、UI スレッド (これが必要です) で実行できるようになります。問題は、SendAsync が DoRefresh の作業を待機しないことです。
SendAsync: "ターゲット メッセージ ブロックに非同期的にメッセージを提供し、延期を可能にします". アクション自体ではなく、送信を待っているだけです。
これを行うと、期待どおりに機能しません。
await Refresh(RefreshArgs.Something);
// other code goes here. It expects the first refresh to be finished.
await Refresh(RefreshArgs.SomethingElse);
// other code goes here. It expects the second refresh to be finished.
ActionBlock は 2 番目の更新をキューに入れますが、更新が完了する前に待機が失敗します。DoRefresh の作業が完了したら、それらを返す必要があります。