2011-10-19 66 views
0

我有這樣的foreach循環:與重構如果一個foreach - 否則,如果結構LINQ

var includedElements = new HashSet<int>(); 
foreach(var e in elements) 
{ 
    var include = false; 
    if(isTable(e.Key)) 
    { 
     if(tables.ContainsKey(e.Key) 
     { 
      if(tables[e.Key].Elements 
       .Any(subElem => shouldBeIncluded(subElem.Key))) 
      { 
       include = true; 
      } 
     } 
    } 
    else if(shouldBeIncluded(e.Key)) 
    { 
     include = true; 
    } 
    if(include){ 
     includedElements.Add(e.Key); 
     DoSomeMoreStuff(e); 
    } 
} 

我試圖重構這對LINQ:

var query = 
    from e in elements 
    where 
    ( 
     isTable(e.Key) 
     && tables.ContainsKey(e.Key) 
     && tables[e.Key].Elements 
       .Any(subElem => shouldBeIncluded(subElem.Key)) 
    ) || (
     !isTable(e.Key) 
     && shouldBeIncluded(e.Key) 
    ) 
    select e; 
foreach(e in query){ 
    includedElements.Add(e.Key); 
    DoSomeMoreStuff(e); 
} 

我不知道怎麼樣這裏是子句。在我的腦海中,我需要包含!isTable(e.Key)來處理外部結構。
我是否正確地對待我的重構?這兩個代碼示例是否導致相同的邏輯功能?

難道只有一次致電isTable我可以逃脫嗎?因爲我現在有了它,所以我需要在||的另一側將它翻轉。

回答

5

是的你是對的。如果isTable沒有副作用(除了檢查某些東西外沒有做任何事情)並且是基於參數的確定性(所以用e.Key調用它兩次總是導致相同的值)。不過它可能(它可能是一個過早的優化...誰知道?)可能是更好地保持它更類似於原始if並使用三元運算符(? :),所以不重新檢查isTable

var query = 
    from e in elements 
    where 
     isTable(e.Key) ? 

      tables.ContainsKey(e.Key) && tables[e.Key].Elements 
       .Any(subElem => shouldBeIncluded(subElem.Key)) 
     : 

      shouldBeIncluded(e.Key) 
    select e; 

我補充一點,如果你恨三元運營商,您可以使用關鍵字let

var query = 
    from e in elements 
    let isT = isTable(e.Key) 
    where 
     (isT && tables.ContainsKey(e.Key) && tables[e.Key].Elements 
      .Any(subElem => shouldBeIncluded(subElem.Key))) 
      || 
     (!isT && shouldBeIncluded(e.Key)) 
    select e; 

緩存isTable(e.Key)

+0

太好了。儘管對'isTable'的檢查沒有什麼特別之處,但它仍然是一個調用來檢查它是否存在於字典中,如果字典很大,這可能會很昂貴。您的解決方案正是我所需要的。 – awe

0

你是對的。該else if意味着if條件不匹配,所以

if(A) { 
    if(B) { 
     if(C) { 
      include = true; 
     } 
    } 
} 
else if(D) { 
    include = true; 
} 

相當於

if(A) { 
    if(B) { 
     if(C) { 
      include = true; 
     } 
    } 
} 

if(!A && D) { 
    include = true; 
} 

這相當於

if ((A && B && C) || (!A && D)) { 
    include = true; 
} 

這是你寫在LINQ什麼。

+0

這個問題並不是真的關於if的布爾邏輯,而是一種重構LINQ而不必調用兩次'isTable'方法的方法。由於它是一種方法,如果方法很重,它可能會成爲性能問題。 – awe