仅停止一个异步方法

18

我有一个方法可以在用户点击屏幕时播放声音,而我希望当用户再次点击屏幕时停止播放声音。但问题是,“DoSomething()”方法不会停止,它会一直执行到完成。

bool keepdoing = true;

private async void ScreenTap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        keepdoing = !keepdoing;
        if (!playing) { DoSomething(); }
    }

private async void DoSomething() 
    {
        playing = true;
        for (int i = 0; keepdoing ; count++)
        {
            await doingsomething(text);
        }
        playing = false;
    }

任何帮助都将不胜感激。
谢谢 :)


尝试将keepdoing声明为volatile bool keepdoing = true;。但是,如果doingsomething需要太长时间才能返回,用户可能会按两次屏幕,从而将keepdoing切换为false,然后再切换回true。 - Matthew Watson
做某事并不花费很长时间,但由于循环,DoSomething()需要时间。我很抱歉地说,但是volatile没有起作用。 - Jaydeep Solanki
易变性(Volatile)不是问题,因为等待(await)之后的代码总是被分派回用户界面线程... 这不是同步问题。 - Rico Suter
2个回答

33

这就是CancellationToken的用途。

CancellationTokenSource cts;

private async void ScreenTap(object sender, System.Windows.Input.GestureEventArgs e)
{
  if (cts == null)
  {
    cts = new CancellationTokenSource();
    try
    {
      await DoSomethingAsync(cts.Token);
    }
    catch (OperationCanceledException)
    {
    }
    finally
    {
      cts = null;
    }
  }
  else
  {
    cts.Cancel();
    cts = null;
  }
}

private async Task DoSomethingAsync(CancellationToken token) 
{
  playing = true;
  for (int i = 0; ; count++)
  {
    token.ThrowIfCancellationRequested();
    await doingsomethingAsync(text, token);
  }
  playing = false;
}

1
应该有一个finally块来将cts设置为null吗?在完成(未取消)运行后,需要两次点击才能运行DoSomethingAsync - Gusdor
@Gusdor:干得好!我进行了修正。它不是很好——CTS可以重复使用而不仅仅是GCed,但它传达了一般的观点。 - Stephen Cleary

5

使用 CancellationToken 的另一种方法是声明/初始化 CancellationTokenSource cts,然后将 cts.Token 传递给 DoSomething,就像 Stephen Cleary 在上面的答案中所述。

private async void DoSomething(CancellationToken token) 
{
    playing = true;
    for (int i = 0; keepdoing ; count++)
    {
        if(token.IsCancellationRequested)
        {
         // Do whatever needs to be done when user cancels or set return value
         return;
        }
        await doingsomething(text);
    }
    playing = false;
}

好的建议,因为在我的情况下它不会是一个例外。 - Leniaal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接