尝试在Windows窗体GroupBox中包含的某些标签上设置属性,我编写了下面的循环。这样做很好,但我不喜欢它,因为它(我认为不必要的)双foreach嵌套。
我试图将其重写为更清楚,只使用一个foreach和一个组合的Linq表达式,但我的所有尝试都在运行时因CastException而失败,从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() == "answer" select a)) tlbl.ForeColor = (tlbl.Name.Replace("lbl", "") == rb.Name) ? afterSelectColor : beforeSelectColor;
可读性是我的最高目标。考虑到这一点,是否值得尝试重写它?
答案 0 :(得分:4)
我建议您在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() == "answer")))
{
tblb.ForeColour = tlbl.Name.Replace("lbl", "") == rb.Name ? afterSelectColor : beforeSelectColor;
}
请注意SelectMany
。这就是你如何将嵌套的foreach
循环转换为LINQ,因为它几乎只是一个嵌套的foreach
循环。
答案 1 :(得分:1)
Controls.OfType<GroupBox>
.SelectMany(x => x.Controls.OfType<Label>)
.Where(x => x.Tag != null && x.Tag.ToString() == "answer")
.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() == "answer")
foreach (var label in labels)
{
label.ForeColor = (label.Name.Replace("lbl", "") == rb.Name) ? afterSelectColor : beforeSelectColor);
}
虽然这将代码分为2个语句,但与其他方法相比,它可以提高可读性。
编辑2:
由于这是winforms,Control.Controls
集合不是IEnumerable<T>
,而是IEnumerable
,因此OfType<T>
必须包含在SelectMany()
表达式中。更正了。