1

キャンセル トークンを実装する非同期コードがあります。それは機能していますが、これが正しい方法であるかどうかはよくわからないので、それについてのフィードバックが欲しいだけです.

実際のコードは次のとおりです。

    /// <summary>
    /// 
    /// </summary>
    private async void SaveData() {

        if (GetActiveServiceRequest() != null)
        {
            var tokenSource = new System.Threading.CancellationTokenSource();


            this.ShowWizardPleaseWait("Saving data...");

            var someTask = System.Threading.Tasks.Task<bool>.Factory.StartNew(() =>
            {

                bool returnVal = false;

                // Set sleep of 7 seconds to test the 5 seconds timeout.
                System.Threading.Thread.Sleep(7000);

                if (!tokenSource.IsCancellationRequested)
                {
                    // if not cancelled then save data

                    App.Data.EmployeeWCF ws = new App.Data.EmployeeWCF ();
                    returnVal = ws.UpdateData(_employee.Data);
                    ws.Dispose();
                }

                return returnVal;

            }, tokenSource.Token);


            if (await System.Threading.Tasks.Task.WhenAny(someTask, System.Threading.Tasks.Task.Delay(5000)) == someTask)
            {
                // Completed
                this.HideWizardPleaseWait();
                if (someTask.Result)
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.OK;
                }
                else
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.Abort;
                }
                btnOK.Enabled = true;
                this.Close();
            }
            else
            {
                tokenSource.Cancel();

                // Timeout logic
                this.HideWizardPleaseWait();
                MessageBox.Show("Timeout. Please try again.")
            }


        }
    }

非同期/待機/キャンセル コードは適切に実装されていますか?

フィードバックに感謝します。

4

1 に答える 1

6

一般に、を使用する必要がありますThrowIfCancellationRequestedTaskこれにより、結果が「正常に完了しました」状態ではなく、キャンセルされた状態で返されるfalse結果が完了します。

その他のポイント:

  • 避けてくださいasync void。これはasync Task、イベントハンドラーでない限り、そうする必要があります。
  • を優先Task.RunTaskFactory.StartNewます。
  • を使用しusingます。
  • CancellationTokenSourceタイムアウトとして使用している場合は、そのための特別な機能があります。Task.Delayを介して別のタスクを作成するTask.WhenAny必要はありません。

更新されたコードは次のようになります。

private async Task SaveData()
{
    if (GetActiveServiceRequest() != null)
    {
        var tokenSource = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(5));
        var token = tokenSource.Token;

        this.ShowWizardPleaseWait("Saving data...");

        var someTask = System.Threading.Tasks.Task.Run(() =>
        {
            // Set sleep of 7 seconds to test the 5 seconds timeout.
            System.Threading.Thread.Sleep(7000);

            // if not cancelled then save data
            token.ThrowIfCancellationRequested();
            using (App.Data.EmployeeWCF ws = new App.Data.EmployeeWCF())
            {
                return ws.UpdateData(_employee.Data);
            }
        }, token);

        try
        {
            var result = await someTask;

            // Completed
            this.HideWizardPleaseWait();
            if (result)
            {
                this.DialogResult = System.Windows.Forms.DialogResult.OK;
            }
            else
            {
                this.DialogResult = System.Windows.Forms.DialogResult.Abort;
            }
            btnOK.Enabled = true;
            this.Close();
        }
        catch (OperationCanceledException)
        {
            // Timeout logic
            this.HideWizardPleaseWait();
            MessageBox.Show("Timeout. Please try again.")
        }
    }
}
于 2013-02-22T15:49:30.937 に答える