C# 使用任务<;列表<;任务>&燃气轮机;C语言中异步递归操作的实现#

C# 使用任务<;列表<;任务>&燃气轮机;C语言中异步递归操作的实现#,c#,asynchronous,recursion,task,C#,Asynchronous,Recursion,Task,假设我有两个类A和B,它们派生自一个接口(比如IAorB)A包含IAorB对象的列表: public interface IAorB { ... } public class A { ... public List<IAorB> Children { get; set; } ... } public class B { ... } 最佳情况下,操作符递归地将返回一个任务列表,我可以在该列表上使用Task.WaitAll()。但是这种方法返回嵌套的列表,

假设我有两个类
A
B
,它们派生自一个接口(比如
IAorB
A
包含
IAorB
对象的列表:

public interface IAorB { ... }

public class A 
{
    ...
    public List<IAorB> Children { get; set; }
    ...
}

public class B { ... }

最佳情况下,
操作符递归地
将返回一个
任务列表
,我可以在该列表上使用
Task.WaitAll()
。但是这种方法返回嵌套的
列表,这可能不是最优的。

我想您只是对语法有点困惑。这应该是您正在寻找的:

// fix method signature, this doesn't run asynchronous code so it needs not be a Task
public IEnumerable<Task> OperateRecursively(A root)
{
    List<Task> tasks = new List<Task>();

    foreach (IAorB child in root.Children)
    {
        if (child is B)
        {
            tasks.Add(SomeOperation(child));
        }
        else
        {
            // 1. change to AddRange since you are adding multiple elements, not one
            // 2. fix name for actual recursion
            // 3. cast child to A since otherwise it wouldn't compile
            tasks.AddRange(OperateRecursivelyA(child as A));
        }
    }

    tasks.Add(SomeOperation(root));

    return tasks;
}

我很抱歉,但我不得不问,你确定你必须像这样解决问题吗?它看起来很难维护,很难理解,也很难执行。@Nikola.Lukovic这是个公平的问题!我想这部分是因为我喜欢递归定义类型的函数式编程(列表、树等)。但是,我也不知道有什么其他的方式来表达它。我的意思是我可以去掉接口,只使用类型
A
,将
B
表示为一种
A
(去掉终端节点和非终端节点之间的区别),但是异步应用递归操作的问题仍然适用。使用这种方法,任何任务都可能以任何顺序结束,你同意吗?
操作性地做什么?因为我在这里没有看到递归,我看到的是
operateracursivelya
return
List
而不是
Task
不要执行
GetType()
来检查某个事物是否是
B
。如果存在
B
的子类型,比如
FancyB
,则其
GetType
将返回
typeof(FancyB)
,而不是
typeof(B)
。使用
is
测试表达式是否属于特定类型。在C#7中,您可以使用新的
is
模式来声明新变量。谢谢!这正是我想做的!只是我在
操作符中有几个
等待
操作,但我想我总是可以
结果
使其同步。@ZacharyLim:不,不,不要使用
结果
。那会让你陷入僵局!今天我没有时间回答你的问题,但是用异步协程编写序列协程仍然有点棘手。这篇文章可能会有帮助:@ZacharyLim啊。。。这就是为什么你应该总是发布一篇文章。如果你用它来编辑你的问题,我会编辑我的答案,但是我使用
等待任务是有原因的。whalll
而不是
任务。WaitAll
@ZacharyLim:还要注意,这个答案中的解决方案并不会懒散地计算任务序列。它遍历子关系的整个传递闭包。如果该树中有一百万个节点,它将生成一个包含一百万个任务的列表,而不是像您所期望的那样,按需一次提取一个任务。如果这是一个要求,那么再说一遍,有办法做到这一点,但你需要更清楚地说明你的要求是什么。@Camiloterivento对此表示抱歉!但是该方法的异步部分实际上是无关紧要的,因为我不应该使用
结果
(正如其他用户所指出的),我也可以在异步方法中以递归方式包装
运算符
,并将结果作为参数传递。
// fix method signature, this doesn't run asynchronous code so it needs not be a Task
public IEnumerable<Task> OperateRecursively(A root)
{
    List<Task> tasks = new List<Task>();

    foreach (IAorB child in root.Children)
    {
        if (child is B)
        {
            tasks.Add(SomeOperation(child));
        }
        else
        {
            // 1. change to AddRange since you are adding multiple elements, not one
            // 2. fix name for actual recursion
            // 3. cast child to A since otherwise it wouldn't compile
            tasks.AddRange(OperateRecursivelyA(child as A));
        }
    }

    tasks.Add(SomeOperation(root));

    return tasks;
}
await Task.WhenAll(OperateRecursivelyA(someRoot));