我如何/应该用一个linq查询替换嵌套的foreach
本文关键字:linq 一个 查询 替换 foreach 嵌套 | 更新日期: 2023-09-27 18:18:21
尝试在Windows窗体组框中包含的某些标签上设置属性,我编写了下面的循环。这工作得很好,但我不喜欢它,因为它的(我认为不必要的)双foreach嵌套。
我试着重写它,使其更清晰,只使用一个foreach和一个组合的Linq表达式,但是我所有的尝试都在运行时失败,从GroupBox到Label或反之亦然。
是否有更清晰、更有效或更可读的方式来编写这个循环结构?
可读性是我的最高目标。考虑到这一点,是否值得尝试重写它?foreach (var gb in (from Control c in this.Controls where c is GroupBox select c)) foreach (Label tlbl in (from Control a in gb.Controls where a is Label && a.Tag != null && a.Tag.ToString() == "answerswer" select a)) tlbl.ForeColor = (tlbl.Name.Replace("lbl", "") == rb.Name) ? afterSelectColor : beforeSelectColor;
我建议您在foreach
中进行编辑,因为LINQ并不意味着会产生副作用。这样的:
foreach (Label tlbl in (this.Controls.OfType<GroupBox>()
.SelectMany(g => g.Controls.Cast<Control>()).OfType<Label>()
.Where(a => a.Tag != null && a.Tag.ToString() == "answerswer")))
{
tblb.ForeColour = tlbl.Name.Replace("lbl", "") == rb.Name ? afterSelectColor : beforeSelectColor;
}
注意这里的SelectMany
。这就是如何将嵌套的foreach
循环转换为LINQ,因为它几乎只是一个嵌套的foreach
循环。
Controls.OfType<GroupBox>
.SelectMany(x => x.Controls.OfType<Label>)
.Where(x => x.Tag != null && x.Tag.ToString() == "answerswer")
.ToList()
.ForEach(x => x ForeColor = (x.Name.Replace("lbl", "") == rb.Name) ? afterSelectColor : beforeSelectColor);
注意ForEach()
方法不是LINQ的一部分。它是List<T>
类的成员。LinQ是一个函数特性,因此它的方法不应该影响源对象。这就是为什么LINQ中没有ForEach()
。
如果您不喜欢使用List<T>.ForEach()
,那么您也可以这样做:
var labels = Controls.OfType<GroupBox>
.SelectMany(x => x.Controls.OfType<Label>)
.Where(x => x.Tag != null && x.Tag.ToString() == "answerswer")
foreach (var label in labels)
{
label.ForeColor = (label.Name.Replace("lbl", "") == rb.Name) ? afterSelectColor : beforeSelectColor);
}
虽然这将代码分成两个语句,但与其他方法相比,它大大提高了可读性。
Edit2:
由于这是winforms, Control.Controls
集合不是IEnumerable<T>
,而是IEnumerable
,因此OfType<T>
必须包含在SelectMany()
表达式中。纠正。