c# - 取消执行并在方法重新进入时重新执行

标签 c# .net task-parallel-library async-await

我看到有人问类似的问题 here但这似乎不太适合我的场景。

我们有一个可以执行请求的 UI,如果用户想要再次执行该请求(使用不同的查询参数),我们希望放弃初始请求,忽略其响应并仅使用最新的请求响应。

目前我有:

private readonly IDataService _dataService;
private readonly MainViewModel _mainViewModel;

private CancellationTokenSource _cancellationTokenSource;

//Constructor omitted for brevity

public async void Execute()
{
    if (_cancellationTokenSource != null)
    {
        _cancellationTokenSource.Cancel();
    }

    _cancellationTokenSource = new CancellationTokenSource();

    try
    {
        string dataItem = await _dataService.GetDataAsync(_mainViewModel.Request, _cancellationTokenSource.Token);
        _mainViewModel.Data.Add(dataItem);
    }
    catch (TaskCanceledException)
    {
        //Tidy up ** area of concern **
    }
}

这似乎运行良好,我有一个漂亮且响应灵敏的用户界面,但我有一个让我担心的场景:

  1. 用户提出请求
  2. 用户发出新请求,该请求取消了原始请求
  3. 新请求在原始取消的请求抛出异常之前返回,并使用当前所需的数据填充 UI
  4. 抛出异常并进行清理,覆盖新的请求输出

这可能非常罕见,但我认为这是一种可能性,除非我对此的理解是错误的。

是否有任何方法可以确保,如果通过取消 token 请求取消任务并启动新任务,则取消会在新任务启动/返回执行之前发生,而不会阻塞 UI 线程?

任何能够扩展我对此的理解的阅读都将不胜感激。

最佳答案

Is there any way to ensure that if a Task is cancelled via a cancellation token request and a new Task is started the cancellation happens before the new task is started/returns execution without blocking the UI thread?

Any reading to expand my understanding on this would be most appreciated.

首先,根据要求提供一些相关的阅读 Material 和问题:

如果我正确理解您的问题,您主要担心的是,同一任务的前一个实例可能会使用过时的结果更新 UI(或 ViewModel),一旦它已完成。

为了确保这种情况不会发生,请在您要更新 UI/模型之前,在各处使用 ThrowIfCancellationRequested 和相应的 token 。 > 你就这么做。那么,任务的最新实例是否先于上一个较旧的实例完成就无关紧要了。较旧的任务将在它可能有机会执行任何有害操作之前到达 ThrowIfCancellationRequested 点,因此您不必等待较旧的任务任务:

public async void Execute()
{
    if (_cancellationTokenSource != null)
    {
        _cancellationTokenSource.Cancel();
    }

    _cancellationTokenSource = new CancellationTokenSource();
    var token = _cancellationTokenSource.Token.

    try
    {
        string dataItem = await _dataService.GetDataAsync(
            _mainViewModel.Request, 
            token);

        token.ThrowIfCancellationRequested();

        _mainViewModel.Data.Add(dataItem);
    }
    catch (OperationCanceledException)
    {
        //Tidy up ** area of concern **
    }
}

另一个问题是,当前一个任务因 TaskCanceledException 以外的任何原因而失败时该怎么办。新任务完成后也可能发生这种情况。由您决定是否忽略此异常、重新抛出它或执行其他操作:

try
{
    string dataItem = await _dataService.GetDataAsync(
        _mainViewModel.Request, 
        token);

    token.ThrowIfCancellationRequested();

    _mainViewModel.Data.Add(dataItem);
}
catch (Exception ex)
{
    if (ex is OperationCanceledException)
        return

    if (!token.IsCancellationRequested)
    {
        // thrown before the cancellation has been requested,
        // report and re-throw
        MessageBox.Show(ex.Message);
        throw;
    }

    // otherwise, log and ignore
}

关于c# - 取消执行并在方法重新进入时重新执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22425321/

相关文章:

.net - 添加对 GAC 的 DLL 的 Web 引用

c# - WCF 双工中的 TPL 数据流 block

c# - TPL 数据流 - ExecutionDataflowBlockOptions.SingleProducerConstrained

c# - 从 HRESULT 创建 COMException

c# - 无法让 WPF ItemsControl 垂直拉伸(stretch)

.net - 在 FolderBrowserDialog 中添加新文件夹

.net - 在 .net 中验证数据

c# - volatile IEnlistmentNotification 和 TransactionScope.AsyncFlowEnabled = true

c# - Xamarin 表格 "...DisplayAlert does not exist in the current context."

c# - Task<ViewResult> 和 ViewResult 之间的区别