C# 如果再次调用异步和正在运行的方法,并且以前的调用结果已过时,如何正确地取消该方法

C# 如果再次调用异步和正在运行的方法,并且以前的调用结果已过时,如何正确地取消该方法,c#,.net,asynchronous,design-patterns,cancellation,C#,.net,Asynchronous,Design Patterns,Cancellation,我有一个相当一般的问题,但有一个特定的用例 在我的特定情况下,我有一个带有输入文本框的UI,如果用户正在更改该输入框中的文本,则会显示一些建议,以供用户最终输入。换句话说,输入框使用自动完成功能。建议是从Web服务请求的,因此此过程花费大量时间,用户可能已经再次更改了文本。因此,我希望取消或停止仍在获取过时数据的进程,只获取最近调用该方法的结果 因此,假设视图类中调用方法GetRecommendationsAsync的方法OnTextChanged。我的方法是简单地取消以前的和过时的GetRec

我有一个相当一般的问题,但有一个特定的用例

在我的特定情况下,我有一个带有输入文本框的UI,如果用户正在更改该输入框中的文本,则会显示一些建议,以供用户最终输入。换句话说,输入框使用自动完成功能。建议是从Web服务请求的,因此此过程花费大量时间,用户可能已经再次更改了文本。因此,我希望取消或停止仍在获取过时数据的进程,只获取最近调用该方法的结果

因此,假设视图类中调用方法GetRecommendationsAsync的方法OnTextChanged。我的方法是简单地取消以前的和过时的GetRecommendationsAsync调用,然后如果该方法被取消,则不在UI中执行任何操作。下面是我刚刚编写的一些最小代码,其中可能包含错误,以显示概念:

public async Task OnTextChangedAsync(string newText)
{
    try
    {
        var recommendations = await GetLatestRecommendationsAsync(newText);
        ShowRecommendations(recommendations);
    }
    catch(TaskCanceledException)
    {
    }
}

private Task<Recommendations[]> GetLatestRecommendationsAsync(string text)
{
     _cancellationTokenSource?.Cancel();
     _cancellationTokenSource = new CancellationTokenSource();

     if (string.IsNullOrWhiteSpace(text)) return null;

     return GetRecommendationsAsync(text, _cancellationTokenSource.Token);
}
现在,我的问题是,这是一个有效的方法还是有一些缺点? 此外,我想知道是否有一个通用的已知模式来处理由于再次调用而取消过时方法的一般情况? 使用信号量的appraoch是否更好? 你会如何处理这个案子? 是否保证在新调用返回其结果之前捕获上一调用的取消

想知道是否有一个通用的已知模式来处理由于再次调用而取消过时方法的一般情况

取消令牌是处理任何原因的取消的一般已知模式

是否保证在新调用返回其结果之前捕获上一调用的取消

否。这是因为取消令牌用于合作取消,这意味着一方请求取消,另一方定期检查取消请求并决定如何取消。这种方法的目的是确保任何需要撤消的操作都已撤消,并且不会使事情处于不稳定状态

与之相比,比如说,在后台线程中执行工作,然后仅仅终止线程以取消。你不知道它是在什么时候被杀死的,也不知道是否有任何东西处于未知或不稳定的状态

如果出于任何原因,您必须确保在知道前一次尝试已停止之前,您甚至不会启动另一次尝试,那么您必须使用信号量之类的东西,可能还需要使用取消令牌。这完全取决于GetRecommendationsAsync正在做什么

旁注:OnTextChangedAsync的签名看起来可疑。它的命名类似于事件,但事件必须返回void

想知道是否有一个通用的已知模式来处理由于再次调用而取消过时方法的一般情况

取消令牌是处理任何原因的取消的一般已知模式

是否保证在新调用返回其结果之前捕获上一调用的取消

否。这是因为取消令牌用于合作取消,这意味着一方请求取消,另一方定期检查取消请求并决定如何取消。这种方法的目的是确保任何需要撤消的操作都已撤消,并且不会使事情处于不稳定状态

与之相比,比如说,在后台线程中执行工作,然后仅仅终止线程以取消。你不知道它是在什么时候被杀死的,也不知道是否有任何东西处于未知或不稳定的状态

如果出于任何原因,您必须确保在知道前一次尝试已停止之前,您甚至不会启动另一次尝试,那么您必须使用信号量之类的东西,可能还需要使用取消令牌。这完全取决于GetRecommendationsAsync正在做什么


旁注:OnTextChangedAsync的签名看起来可疑。它的名称类似于事件,但事件必须返回为空。

对我来说似乎有效。对我来说似乎有效。很好的解释。你不能只是去取消其他已经运行的代码。很好的解释。您不能只是到处取消已经运行的其他代码。