繁体   English   中英

使用Linq从具有特定属性的树中获取所有对象

[英]Get all objects from a tree with a particular property using Linq

我有一个类似的类结构:

class TestResults {
   public bool IsSuccess;
   public bool IsFailure;

   public IList<TestResults> SubTestResults;
}

因此,一个测试有多个子测试,以上内容捕获了结果。

我想找到所有具有IsFailure = true的TestResults。

从...开始:

var failures = from result in results
               where result.IsFailure
               select result;

这给了我具有IsFailure = true的顶级结果,但是我想获得所有具有IsFailure = true的测试和子测试,并将所有这些和子项都列在列表中。 是否有一个linq查询可以做到这一点,还是应该使用老式循环?

更新:我应该说我对这些类的用法意味着树只有2个深度(类的结构不在我的控制之下)。

所以我有:

Test1 - SubTest11
        SubTest12
        SubTest13

Test2 - SubTest21
        SubTest22

Test3 - SubTest31
        SubTest32
        SubTest33
        SubTest34

我需要所有具有IsFailure = true的子测试。

如果只有两个级别(即子测试不能有子测试),则可以执行以下操作:

var failures = results.Union(results.SelectMany(r => r.SubTestResults))
                      .Where(r => r.IsFailure);

这将获取结果列表,并将其与所有结果子级列表合并。

如果您可以具有任意深度的子测试,那么您将需要更复杂的东西,因此我们首先为递归定义一个辅助函数。

IEnumerable<TestResults> AllResults(IEnumerable<TestResults> results)
{
    foreach(var tr in results)
    {
        yield return tr;
        foreach(var sr in AllResults(tr.SubTests))
            yield return sr;
    }
}

现在我们使用它并进行过滤

var failures = from result in AllResults(results)
               where result.IsFailure
               select results;

这应该可以解决问题。 但是,我上面的AllResults的实现不是特别有效( 有关详细信息,请参见Wes Dyers博客 ),因此您确实希望对AllResults执行典型的递归到迭代转换。

IEnumerable<TestResults> AllResults(IEnumerable<TestResults> results)
{
    var queued = new Queue<TestResult>(results); 
    while(queued.Count > 0)
    {
        var tr = queued.Dequeue();
        yield return tr;
        foreach(var sr in tr.SubTests)
            queued.Enqueue(sr);
    }
}

请注意,您仍应添加各种null检查以确保完整性

您需要一个递归表达式来执行此操作,因此请执行以下操作:

Func<TestResult, IEnumerable<TestResult>> func = null;
func = r => r.Tests == null
            ? Enumerable.Empty<TestResult>()
            : r.Tests.Where(t => t.IsFailure)
                     .Union(r.Tests.SelectMany(r2 => func(r2)));

var failures = func(tree);

您唯一需要做的就是在失败时包括根项目。 希望您会注意到该语句在声明和赋值之间分开,这是因为如果您尝试直接在声明中分配递归委托,则会发生编译器错误。

尝试这个:

var failures = from result in results
               where result.GetType().GetProperty("IsFailure") != null
               select result;

或者,让您的测试类继承自通用基类(例如TestBase),然后像这样编写查询:

var failures = from result in results
               where result is TestBase
               select result;

编辑:嗯,我想我在第一次通读时就误解了你的问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM