2013-06-14 3 views
2

Windows Forms GroupBox에 포함 된 특정 레이블에 속성을 설정하려고 시도하면서 아래 루프를 작성했습니다. 이것은 잘 작동하지만, 나는 그것 (나는 불필요한) 이중 foreach 중첩 때문에 그것을 좋아하지 않아.중첩 된 foreach를 하나의 linq 쿼리로 대체하는 방법은 무엇입니까?

하나의 foreach와 결합 된 Linq 표현식을 사용하여 더 명확하게 다시 작성하려고 시도했지만 모든 런타임 오류가 GroupException에서 CastBox로 또는 그 반대로 CastException과 함께 런타임에 실패합니다.

이 루프 구문을 작성하는 데 더 명확하고, 효율적이며, 더 읽기 쉬운 방법이 있습니까?

 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

LINQ는 부작용이 없으므로 foreach에서 편집하는 것이 좋습니다. 이와 같이 :

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 루프입니다.

+0

@Servy 방금 배웠습니다. 감사! –

+1

@Servy도 완료되었습니다. –

+0

좋은 답변입니다. 그러나 나는 이것을 가장 잘 읽고, 에릭 리 퍼트 (Eric Lippert)가 권고하는 부작용이 없다는 것을 알았다. 감사! – shipr

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); 
} 

를, 그것은 향상 가독성은 다른 접근법에 비해 많이 있습니다.

Edit2가이 이후

Control.Controls 컬렉션은 IEnumerable<T> 아니다하지만 IEnumerable 따라서 OfType<T>SelectMany() 식 안에 포함되어야 윈폼이다. 그것을 바로 잡았습니다.

+1

많이 빠졌지 만 거의 다 나와 있습니다. –

+0

@newStackExchange right. 그것을 정정하십시오. –

+0

LINQ는 LinQ가 아니라 이전처럼 철자가 있습니다. –

관련 문제