2

尝试在 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;

可读性是我的最高目标。考虑到这一点,是否值得尝试重写它?

4

2 回答 2

4

我建议您在 a 中进行编辑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循环。

于 2013-06-14T16:34:45.613 回答
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 是一个功能特性,因此它的方法不应该影响源对象。ForEach()这就是LINQ中没有的原因。

编辑:

如果您不喜欢使用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()表达式中。更正了。

于 2013-06-14T16:34:31.443 回答