2010-02-18 63 views
1

給定以下代碼,是否有更好的方法來構造它?循環中的嵌套條件

foreach(Thing item in SomeRandomList) 
{ 
    bool firstCondition = CalculateBool(item, someValue); 
    bool secondCondition = CalculateBool(item, someOtherValue); 

    //General things are done... 
    if(firstCondition || secondCondition) 
    { 
     //semi-specific things are done... 
     if(firstCondition) 
     { 
      //specific things are done... 
     } 
     else 
     { 
      //specific things are done... 
     } 
    } 
} 

另外,如果有更多的條件,即3:

foreach(Thing item in SomeRandomList) 
{ 
    bool firstCondition = CalculateBool(item, someValue); 
    bool secondCondition = CalculateBool(item, someOtherValue); 
    //imagine as many more as you want. 
    bool nthCondition = CalculateBool(item, lastOtherValue); 

    //General things are done... 
    if(firstCondition || secondCondition || nthCondition) 
    { 
     //semi-specific things are done... 
     if(firstCondition) 
     { 
      //specific things are done... 
     } 
     else if(secondCondition) 
     { 
      //specific things are done... 
     } 
     else 
     { 
      //specific things are done... 
     } 
    } 
} 
+3

外部條件似乎如果你想具體的行執行任何情況下 –

+0

冗餘對於特定的條件組合,你會陷入意大利麪。但就你的例子而言,西蒙是正確的 - 你的條件是相互排斥和優先考慮的,所以只要不把它們放在一起即可。 – Potatoswatter

+0

您尚未提供足夠的信息來說明您要完成的任務,那麼如何才能說明是否有更好的方法來組織您的代碼呢? –

回答

3

如果你能具體細分後做特定半的事情,你可以試試這個:

bool anyTrue = true; 

if (firstCondition) 
{ 
    // Specific things 
} 
else if (secondCondition) 
{ 
    // Specific things 
} 
else 
{ 
    // Specific things 
    anyTrue = false; 
} 

if (anyTrue) 
{ 
    // Semi-specific things 
} 

我不知道它是否更好,但它是不同的...

或者,我不是全部在C#3.0和看中新的LINQ的東西,但如果它的表現力足夠,你可以嘗試像(僞代碼):

bool[] conditions = 
{ 
    CalculateBool(item, someValue), 
    CalculateBool(item, someOtherValue), 
    ... 
}; 

if (conditions.AnyTrue) 
{ 
    switch (conditions.IndexOfFirstTrueItem) 
    { 
     case 0: 
      // Specific things 
      break; 

     case 1: 
      // Specific things 
      break; 

     default: 
      // Specific things 
      break; 
    } 
} 
6

是:多態性。

派生Thing的從一個共同的底座(或定義所有Thing接口的實現)

做不到這一點,移動條件測試代碼到一個方法上Thing

+2

「條件」很可能與類型無關。你可能會用這種結構處理兩個不同的數字範圍,但不要爲小數字創建一個類型。 – Potatoswatter

0

我可能一直沒能得到問題的權利,我們只能有2結果,如果函數返回類型booln結果,除非是Nullable<bool>,這可能返回null也。

所以

bool result = CalculateBool(item, someValue); 

if(result) {} 
else {} 

將做到這一點。

關於管理大if/else組合?一種方法是使用Switch語句,這可以提高可讀性。

但在任何情況下,一種方法應該始終有儘可能少的決策路徑,這被稱爲

如果發生這種情況,分割該代碼爲更適當的方法

2

我會使用一些LINQ來使用中間查詢來幫助減少循環中的邏輯:

// Get condition in the query. 
var query = 
    from item in SomeRandomList 
    let condition1 = CalculateBool(item, someValue1) 
    let condition2 = CalculateBool(item, someValue2) 
    ... 
    let conditionN = CalculateBool(item, someValueN) 
    where 
     condition1 || condition2 || ... || conditionN 
    select new { Item = item, 
     Condition1 = condition1, Condition1 = condition2, ... 
     ConditionN = conditionN }; 

foreach(var item in query) 
{ 
    //semi-specific things are done... 
    if(firstCondition) 
    { 
     //specific things are done... 
    } 
    else 
    { 
    //specific things are done... 
    } 
} 

希望這會大大減少循環中的代碼量。

在我看來,雖然你有一系列值被傳遞給CalculateBool爲SomeRandomList中的每個項目。如果是這樣的話,那麼你可以很容易地生成一個查詢該做交叉聯接和過濾器上:

// Get all valid items across all values. 
var query = 
    from item in SomeRandomList 
    from value in someValues 
    where CalculateBool(item, value) 
    select { Item = item, Value = value }; 

// Iterate and process. 
foreach (var item in query) 
{ 
    // Use item.Item and item.Value. 
    // Specifically, use item.Value to perform a lookup 
    // in a map somewhere to determine the course of action 
    // instead of a giant switch statement. 
} 

這工作,因爲你的條件語句表明您只會有一個值對每個項目設定。

2

我喜歡使用字典Predicate<T>及其相關Action s的方法。我回答了類似的問題在這裏:

Coming out of the habit of writing ifs/elseifs for every possible condition

要修改它一下你的問題:

Dictionary<Predicate<Something>, Action> mappings = {{...}} 
bool shouldDoAnything = mappings.Keys.Aggregate(true, (accum, condition) => 
    accum || condition); 

if (shouldDoAnything) 
{ 
    //do semi-specific things 

    foreach(DictionaryEntry<Predicate<Something>, Action> mapping in mappings) 
    { 
     if (mapping.Key(input)) 
     { 
     mapping.Value(); //do specific things 
     break; 
     } 
    } 
} 
0
foreach(Thing item in SomeRandomList) 
{ 
    DoGeneralThings(); //pass in whatever your require to the method 

    if(FirstCondition(item, someValue)) 
    { 
     DoThingsWhenAnyConditionIsTrue(); //pass in whatever your require to the method 
     DoSpecificThingsForFirstCondition(); //pass in whatever your require to the method 
     continue; 
    } 

    if(SecondCondition(item, someValue)) 
    { 
     DoThingsWhenAnyConditionIsTrue(); //pass in whatever your require to the method 
     DoSpecificThingsForSecondCondition(); //pass in whatever your require to the method 
     continue; 
    } 
}