在循环中嵌套条件

时间:2010-02-18 01:23:03

标签: c#

鉴于以下代码,是否有更好的方法来构建它?

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...
        }
    }
}

6 个答案:

答案 0 :(得分:6)

是:多态性。

从公共基础派生Thing(或定义所有Thing实现的接口)

如果失败,请将条件测试代码移到Thing上的方法中。

答案 1 :(得分: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;
    }
}

答案 2 :(得分: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... 
    } 
}

希望这会极大地减少循环中的代码量。

在我看来,虽然你有一系列的值被传递给了SomeRandomList中每个项目的CalculateBool。如果是这种情况,那么您可以轻松生成一个查询,该查询执行交叉连接并对其进行过滤:

// 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.
}

这样可行,因为您的条件表明您只为每个项目设置了一个值。

答案 3 :(得分:2)

我喜欢使用Predicate<T>及其相关Action字典的方法。我在这里回答了类似的问题:

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

答案 4 :(得分:0)

我可能无法正确回答问题,如果函数的返回类型为2而非bool结果,则我们只能得{4}}结果,除非它是{{3也可以返回null。

所以

n

会这样做。

关于管理大型bool result = CalculateBool(item, someValue); if(result) {} else {} 组合?一种方法是使用Nullable<bool>语句,这可以提高可读性。

但无论如何,方法应始终具有最少的可能决策路径,这称为

如果发生这种情况,请将代码拆分为更合适的方法

答案 5 :(得分: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;
    } 
}