我有一个类结构,如下所示:
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的子测试。
答案 0 :(得分: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);
}
}
请注意,您仍应添加各种空检查以确保完整性
答案 1 :(得分: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);
您唯一需要做的就是包含根项目(如果失败)。您可能会注意到声明在声明和赋值之间被分开,这是因为如果您尝试在声明中直接指定递归委托,则会发生编译器错误。
答案 2 :(得分: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;
编辑:嗯,我想我在第一次阅读中误解了你的问题