2014-10-30 3 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; 
    }  
} 

Я хочу найти узел в дереве с именем «Foo» , Для того, чтобы сделать это я:

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

У меня есть 3 цели

  1. Есть метод TraverseTree траверс дерева с выходом (IEnumerable), так что если 3th узел происходит иметь имя = = "Foo", тогда мне не нужно пересекать все дерево. Прямо сейчас этот случай является истинным.
  2. Сделайте способ TraverseTree бежать по отдельной теме, потому что это может занять много времени. Поэтому, наверное, метод TraverseTree должен принимать параметр callBack?
  3. Наконец, будет приятно отменить эту операцию. Нужно ли мне также передать этому методу маркер отмены?

Каков правильный способ сделать это?

К сожалению, я забыл упомянуть, я использую .Net Framework 4,0

+0

Этот ответ Помогите? http://stackoverflow.com/a/20281941/1210520 –

+0

Возможный дубликат [Как вернуть возвращаемый элемент при выполнении Task.WhenAny] (http://stackoverflow.com/questions/18284169/how-to-yield-return- item-when-doing-task-whenany) –

ответ

1
  1. Это уже сделано с кодом, который у вас есть. Yay для отсроченного исполнения.
  2. На сегодняшний день проще всего сделать это синхронно и переместить весь запрос в другой поток.
  3. Да, a 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

Я не знаю, кто голосует, но будет приятно узнать почему. Я попробую это скоро. –

Смежные вопросы