2010-07-07 49 views
2

我有一个类的结构,它看起来像一个特定属性:获得从树中的所有对象与使用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 =真正的顶级效果,但我想所有的测试,并分测验,其中有IsFailure =真实的,并让所有的这些在列表中。有没有可以做到这一点的linq查询,或者我应该使用老式的循环?

更新: 我应该说我对这些类的使用意味着树只有2深(类的结构不受我控制)。

所以我必须:

Test1 - SubTest11 
     SubTest12 
     SubTest13 

Test2 - SubTest21 
     SubTest22 

Test3 - SubTest31 
     SubTest32 
     SubTest33 
     SubTest34 

我需要所有那些有IsFailure =真正的测验。

+0

什么是树的深度,只有一个或两个或任意数量? – Skurmedel 2010-07-07 16:22:43

+0

@Skurmedel:我已经更新了包含深度信息的问题。 – 2010-07-07 16:30:08

回答

4

如果它只是两个级别(即分测试不能有子测试),那么你可以这样做:

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 blog for details),因此您确实希望在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检查的完整性

0

试试这个:

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; 

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

2

你需要一个递归式要做到这一点,所以给出这样的:

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); 

你需要做的唯一的事情,如果失败,则包含根项目。您将希望注意到声明在声明和赋值之间被拆分,这是因为如果您尝试直接在声明中分配递归委托,则会发生编译器错误。