我应该如何/应该用一个linq查询替换嵌套的foreach?

时间:2013-06-14 16:30:31

标签: c# winforms linq foreach nested

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

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

2 个答案:

答案 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()表达式中。更正了。