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.")
            }


        }
    }

async / await / 取消代码是否得到很好的实现?

感谢并感谢您的反馈。

4

1 回答 1

6

一般来说,您应该使用ThrowIfCancellationRequested. 这将Task在取消状态下完成返回,而不是在“成功运行到完成”状态下返回false结果。

其他要点:

  • 避免async void。这应该是async Task除非它是一个事件处理程序。
  • Task.RunTaskFactory.StartNew喜欢.
  • 使用using.
  • 如果您只是CancellationTokenSource用作超时,那么它具有特殊功能。没有必要通过Task.Delayand创建单独的任务。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 回答