2014-10-30 38 views
1

我有以下节点:让IEnumerable的方法异步

class Node 
{ 
    public string Name;   
    public IEnumerable<Node> Children; 
} 

我有以下的扩展方法:

public static class ExtensionMethods 
{ 
    public static IEnumerable<Node> TraverseTree(this Node root) 
    { 
     if (root.Children != null) 
     { 
      foreach (var child in root.Children) 
      { 
       var nodes = TraverseTree(child); 
       foreach (var node in nodes) 
       { 
        yield return node; 
       } 
      } 
     } 

     yield return root; 
    }  
} 

我想搜索在名为“富”树中的一个节点。为了做到这一点我做的:

Node myNode = /* some large tree! */ 
var search = myNode.TraverseTree().Where(x=>x.Name == "Foo").FirstOrDefault(); 

我有3个进球

  1. 有方法TraverseTree横向与产量(IEnumerable的)树,这样,如果这是第3节点恰好有名称= =“Foo”,那么我不必遍历整个树。 现在这种情况是真的
  2. 使方法TraverseTree在单独的线程上运行,因为它可能需要很长时间才能找到。所以我猜TraverseTree方法应该带一个callBack参数?
  3. 最后,它将很高兴能够取消该操作。我是否还需要传递给该方法的取消令牌?

这样做的正确方法是什么?

对不起,我忘了提我使用.NET Framework 4.0

+0

请问这个答案 帮帮我? http://stackoverflow.com/a/20281941/1210520 – 2014-10-30 21:34:43

+0

可能的重复[如何在产生Task.WhenAny时返回项目](http://stackoverflow.com/questions/18284169/how-to-yield-return- item-when-doing-task-whenany) – 2014-10-30 21:35:09

回答

1
  1. 这已经是与你的代码来完成。耶延期执行。
  2. 到目前为止,这样做的更简单的方法是保持方法同步并将整个查询移动到另一个线程中。
  3. 是的,一个CancellationToken是由遍历算法,你的孩子选择器,或两者都检查,肯定是你可以添加。另一种选择是只是等待遍历停止等待的结果,而不是试图实际停止计算发生。
0

首先,我想实现你的功能,像这样(请注意使用的CancellationToken

public static IEnumerable<Node> TraverseTree(this Node root, CancellationToken token) 
{ 
    if (root.Children != null) 
    { 
     foreach (var child in root.Children) 
     { 
      if (token.IsCancellationRequested) return; //cancel if requested. 

      var nodes = TraverseTree(child); 
      foreach (var node in nodes) 
      { 
       yield return node; 
       if (token.IsCancellationRequested) return; //cancel if requested. 
      } 
     } 
    } 

    yield return root; 
}  

然后,这里是电话会是什么样子:

var cts = new CancellationTokenSource(); 

var task = Task.Run(
    () => myNode.TraverseTree(cts.Token).Where(x=>x.Name == "Foo").FirstOrDefault(), 
    cts.Token); 

再后来如果你想取消,你只需拨打:

cts.Cancel(); 
+0

我不知道谁投了票,但它会很高兴知道为什么。我会尽快尝试。 – 2014-10-30 22:33:07