如何在LINQ查询中取消异步操作?

时间:2013-08-01 11:23:52

标签: c# wpf linq task

这个问题扩展了我之前的Asynchronuos binding and LINQ query hangs。假设我有一个像我们这样的LINQ:

var query = from var item in items where item.X == 1 select item;

我可以异步遍历query并将每个项目分发到UI(或者我可以使用IProgress):

foreach(var item in query)
{
    Application.Current.Dispatcher.BeginInvoke(
        new Action(() => source.Add(item)));
}

现在我想取消查询...我可以简单地声明一个CancellactionTokenSource cts,将一个令牌放入任务然后:

foreach(var item in query)
{
    cts.Token.ThrowIfCancellationRequested();

    Application.Current.Dispatcher.BeginInvoke(
        new Action(() => source.Add(item)));
}

麻烦的是,我只有在出现新结果时才能取消。因此,如果有一长串项目不符合我的查询条件,我的取消请求将被忽略。

如何将取消纳入LINQ(对象)并能够检查每个项目的取消令牌?

2 个答案:

答案 0 :(得分:1)

我不确定,因为我没有测试它...但我认为你可以把它作为副作用放在你的linq查询中,也许在你的位置创建一个方法,例如:

改变这个:

var query = from var item in items where item.X == 1 select item;

要:

var query = from var item in items where CancelIfRequestedPredicate(item,i=>i.X == 1) select item;

并创建一个方法:

private bool CancelIfRequestedPredicate<T>(T item,Predicate<T> predicate)
{
   cts.Token.ThrowIfCancellationRequested();
   return predicate(item);
}

由于linq使用延迟执行,我认为它将在每次迭代时运行您的方法。

就像观察一样,我不知道如果你没有使用Linq到对象会有什么行为(你没有提到你是否正在使用linq到sql,或类似的东西)。但它可能不起作用。

希望它有所帮助。

答案 1 :(得分:0)

对于我这个问题的特定于Entity Framework版本:

当我终于找到了一个明确的答案(对我来说)时,我一直在努力寻找答案,直到找到答案(我访问过的30页网页之一)。 这个问题特别是针对实体框架运行的linq查询。

对于更高版本的Entity Framework(截至目前) 有一些ToListAsync扩展方法,其中包括带有取消令牌的重载。

与任务(在我的情况下,我的查询是在任务中)一样,我也在其中运行了查询,但这是我最关心的数据查询。

var sourceToken = new System.Threading.CancellationTokenSource();

var t2 = System.Threading.Tasks.Task.Run(() =>
  {
    var token = sourceToken.Token;
    return context.myTable.Where(s => s.Price == "Right").Select(i => i.ItemName).ToListAsync(token);
  }

  , sourceToken.Token
);