编码大型嵌套功能块时的经验法则

时间:2010-10-04 16:39:10

标签: c# refactoring

我已经在c#编写了一段时间,并且通常对编码标准的经验法则有很好的了解。我最近鼓励我的大学采用基于结果的方法来编写功能块而不是嵌套逻辑块,并且正在寻求你的建议。下面是我正在谈论的一个例子,其中一种情况的结果用于确定代码路径而不是嵌套。有人建议这种方法更容易阅读,特别是如果结果需要多层嵌套,但我更喜欢使用Curly’s Law并重构嵌套变深的方法和函数。

private void MethodOne()
    {

        bool CarryOn = false;

        // first layer
        if (ValidationRuleOne() == true)
        {
            CarryOn = true;

        } else {

            CarryOn = false;
        }

        // second layer
        if (CarryOn) 
        {
            CarryOn = ValidationRuleTwo();

        } else {

            CarryOn = false;
        }

        // third layer
        if (CarryOn)
        {
            CarryOn = ValidationRuleThree();

        } else
        {

            CarryOn = false;
        }

    }

这种方法对我来说似乎不对,因为我建议将该方法重写为..

        private void MethodOne()
    {



        // first layer
        if (ValidationRuleOne() == true)
        {

            // second layer
            if (ValidationRuleTwo() == true)
            {

                // third layer
                if (ValidationRuleThree() == true)
                {


                }

            }
        }

    }

如果嵌套变得过于复杂,那么我建议需要重新考虑方法/功能结构,将逻辑功能组分组到其他方法或函数中吗?

任何想法都非常感激。

问候,

8 个答案:

答案 0 :(得分:10)

if (ValidationRuleOne() == true)
    {

        // second layer
        if (ValidationRuleTwo() == true)
        {

            // third layer
            if (ValidationRuleThree() == true)

可以是:

if(ValidationRuleOne() && ValidationRuleTwo() && ValidationRuleThree())
{
...
}
在我看来,

更容易阅读。

如果出于某种原因需要启动每个验证规则:

if(ValidationRuleOne() & ValidationRuleTwo() & ValidationRuleThree())
{...} //note the & vs &&

(你不需要做if(validationRule()== true),因为验证返回一个布尔值,你不需要将它与条件语句中的一个进行比较)。

答案 1 :(得分:7)

我个人喜欢使用保护条款。

if (!ValidationRuleOne()) 
    return;

if (!ValidationRuleTwo())
    return;

if (!ValidationRuleThree()) 
    return;

答案 2 :(得分:6)

您是不是只是从else块返回而不是将“CarryOn”设置为false的原因?

我同意Kevin的使用&&的建议,如果你没有别的事可做......我假设在现实生活中你在if和else块中有其他代码。如果你不这样做,绝对应该只使用&&

另外,就风格而言:

  • 不要将布尔值与true或false进行比较:

    if (ValidationRuleOne() == true)
    

    通常应该是

    if (ValidationRuleOne())
    
  • 在camelCase中命名局部变量,因此carryOn代替CarryOn

  • 如果要在每个路径中设置变量(如在第一个if / else中),请不要立即分配...该值将被丢弃。

答案 3 :(得分:3)

我更愿意:

private bool IsValid()
{
    return ValidationRuleOne() && ValidationRuleTwo() && ValidationRuleThree();
}

答案 4 :(得分:1)

另一种选择是使用:

if (!ValidationRuleOne()) return;
// Do some work
if (!ValidationRuleTwo() || !ValidationRuleThree()) return;

// The main body

这有几个好处

  • 您可以在检查各种验证规则之间执行其他工作
  • ..但如果您不需要额外的工作,您仍然可以在一行中轻松验证更多内容。
  • 您可以避免将代码向右缩进(嵌套if s会发生这种情况)

唯一的限制是您可能需要将其移动到单独的方法中,以便在验证不成立时使用return退出方法。

答案 5 :(得分:1)

保持功能性 - 如果您可以在C#中使用lambda表达式,这正是您可以使用continuation的情况,在您的情况下,每个验证例程的continuation只有在验证通过时才会执行

  ValidationRuleOne(() => ValidationRuleTwo(() => ValidationRuleThree()));

public void ValidationRuleOne(Action continuation)
{
  //...

 if(validationSuccessful  && continuation!=null)
    continuation();
}

答案 6 :(得分:0)

我经历过两者,我相信两者都可以。我认为,它实际上归结为个人偏好和易用性/理解。

答案 7 :(得分:0)

对于给出的例子,@ Darin Dimitrov的解决方案是最好的。

如果根据验证结果采取其他措施,显而易见的解决方案是goto

private void MethodOne() 
{ 

    bool isValid = false; 

    // first layer 
    isValid  = ValidationRuleOne();
    if (!isValid) { goto tagApplyValidationResult; }

    isValid  = ValidationRuleTwo();
    if (!isValid) { goto tagApplyValidationResult; }

    isValid  = ValidationRuleThree()

 tagApplyValidationResult:
    if (!isValid) { Whine(); }
    else          { DoTheHappyDance(); }
}