簡體   English   中英

C#重構If語句

[英]C# Refactoring of If Statement

我正在嘗試使用C#的不同領域並重構最佳實踐/模式。

可以看出,下面的Validate方法具有3個子驗證方法。

有沒有一種方法可以重新設計此方法/對其進行重構,以便刪除if語句? (可能使用委托嗎?)。

您還會建議哪些常規代碼標准改進?

public bool Validate()
{            
     bool validDump;

     validDump = ValidateRecordIdentifiers();
     if (!validDump)
     {
         LogLogic.AddEntry(LogLogic.GetEnumDescription(
              LogMessages.StatusMessages.JobValidationFailed));
         return false;
     }

     validDump = ValidateTotals();
     if (!validDump)
     {
         LogLogic.AddEntry(LogLogic.GetEnumDescription(
              LogMessages.StatusMessages.JobValidationFailed));
         return false;
     }

     validDump = ValidateRecordCount();
     if (!validDump)
     {
         LogLogic.AddEntry(LogLogic.GetEnumDescription(
              LogMessages.StatusMessages.JobValidationFailed));
         return false;
     }

     LogLogic.AddEntry(LogLogic.GetEnumDescription(
          LogMessages.StatusMessages.JobValidationPassed));
     return true;
}
    bool valid = false; 
       if(ValidateRecordIdentifiers() && ValidateTotals() && ValidateRecordCount())
        {
          valid = true;
        }


/******AN Alternate Suggestion for the above code********/
    bool valid =  ValidateRecordIdentifiers() && 
                  ValidateTotals() && 
                  ValidateRecordCount();
/*******End Alternate Suggestion*************/


   var statusMessage = (valid) ? 
       LogMessages.StatusMessages.JobValidationPassed :
       LogMessages.StatusMessages.JobValidationFailed

   LogLogic.AddEntry(LogLogic.GetEnumDescription(statusMessage));

   return valid;

請參閱短路: http : //msdn.microsoft.com/zh-cn/library/2a723cdk%28VS.71%29.aspx

框架:

class Validator
{
    Func<bool> validatorDelegate;
    Action failDelegate;

    public Validator(Func<bool> v, Action fail)
    {
        validatorDelegate = v;
        failDelegate = fail;
    }

    public bool Validate()
    {
        bool rc = validatorDelegate();
        if (!rc) failDelegate();
        return rc;
    }
}

class ValidatorCollection : List<Validator>
{
    Action successDelegate;
    Action failDelegate;

    public ValidatorCollection(Action failDelegate, Action successDelegate)
    {
        this.successDelegate = successDelegate;
        this.failDelegate = failDelegate;
    }

    public bool Validate()
    {
        var rc = this.All(x => x.Validate());
        if (rc) successDelegate();
        return rc;
    }

    public void Add(Func<bool> v)
    {
        this.Add(new Validator(v, failDelegate));
    }
}

用法:

class test
{
    public bool Validate()
    {
        return new ValidatorCollection(
            FailAction,
            SuccessAction)
        {
            valTrue,
            valTrue,
            valFalse
        }.Validate();
    }

    public void FailAction()
    {
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed));
    }

    public void SuccessAction()
    {
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed));
    }

    public bool valTrue()
    {
        return true;
    }
    public bool valFalse()
    {
        return false;
    }
}

您可以修改您的驗證方法,以使它們接受LogLogic參數並為失敗添加自己的條目。

他們仍然可以返回布爾值,並且該值可以用來使您盡快返回。

return ValidateRecordIdentifiers(LogLogic) 
    && ValidateTotals(LogLogic) 
    && ValidateRecordCount(LogLogic);
public bool Validate()
{
    return Validate(ValidateRecordIdentifiers, ValidateTotals, ValidateRecordCount);
}

public bool Validate(params Func<bool>[] validators)
{
    var invalid = validators.FirstOrDefault(v => !v());
    if (invalid != null)
    {
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed));
        return false;
    }
    LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed));
    return true;
}

跳出來的第一件事是重復:LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed));

所以我希望將其折疊成類似以下內容:

public StatusMessages Validate() {

  LogMessages.StatusMessages status = LogMessages.StatusMessages.JobValidationFailed;

  if( ValidateRecordIdentifiers() && ValidateTotals() && ValidateRecordCount())
    status = LogMessages.StatusMessages.JobValidationPassed;

  LogLogic.AddEntry(status.ToString());

  return status;
}

無論哪個驗證功能失敗,您都在寫相同的錯誤消息。 在每種情況下記錄特定的錯誤消息可能會更有用。 否則,您可以重寫已經很簡單的內容:

if (ValidateRecordIdentifiers() && ValidateTotals() &&  ValidateRecordCount())
{
    LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed));
    return true;
}
LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed));
return false;

有很多不同的方法可以編寫此代碼,但是您的方法簡短易讀。 到目前為止,imo所發布的建議可讀性更差,更難調試(您將在哪里設置斷點?)。 我將保持這種方法不變,並尋找其他重構機會。

您可以執行以下簡單操作:

bool validDump;
string message;
if ((!ValidateRecordIdentifiers()) ||
    (!ValidateTotals()) ||
    (!ValidateRecordCount()))
{
    message = LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed);
}
else
{
    message = LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed);
    validDump = true;
}
LogLogic.AddEntry(message);
return validDump;

在我看來,這似乎是結構化異常處理的一種情況。 從某種意義上來說,您正在處理的異常情況似乎已經輸入了無效的東西,這導致放棄了該過程。 您是否考慮過在父函數中使用try / catch並在子函數中拋出以處理此問題?

例:

public bool Validate()
{
   try
   {
      ValidateRecordIdentifiers();
      ValidateTotals();
      ValidateRecordCount();
      LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed));
      return true;
   }
   catch (ValidationException ex)
   {
      LogLogic.AddEntry(ex.status);
      return false;
   }
}

class ValidationException : ApplicationException
{
   public readonly LogMessages.StatusMessages status;
   ValidationException(LogMessages.StatusMessages status)
   {
      this.status = status;
   }
}

void ValidateRecordIdentifiers()
{
   if (bad)
      throw new ValidationException(LogMessages.StatusMessages.JobValidationFailed);
}

void ValidateTotals()
{
   if (bad)
      throw new ValidationException(LogMessages.StatusMessages.JobValidationFailed);
}

void ValidateRecordCount()
{
   if (bad)
      throw new ValidationException(LogMessages.StatusMessages.JobValidationFailed);
}

編輯:我一般不喜歡對不會立即報告給UI的錯誤使用異常處理,因為異常處理的成本可能很高,並且如果您嘗試查找真正的異常,過多的異常拋出可能會使應用程序更難以調試一堆不是真正的“例外”的例外。 但是根據您的具體情況,這可能是適當的。 請謹慎使用。

也許:

public bool Validate() 
{

        if (ValidateRecordIdentifiers() && ValidateTotals() && ValidateRecordCount())
        {
           LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed));
           return true;
        }

        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed));

        return false;
    }

您的函數執行兩件事:驗證和日志記錄。 您可以像這樣將它們分開。 如果您決定這樣做,這也可以讓您以不同的方式記錄這些錯誤。

public bool ValidateAndLog()
{
    LogMessages.StatusMessages result=Validate();
    LogLogic.AddEntry(LogLogic.GetEnumDescription(result));
    return result==LogMessages.StatusMessages.JobValidationPassed;
}

private LogMessages.StatusMessages Validate()
{
    //of course you can combine the next three ifs into one 
    if (!ValidRecordIdentifiers())
        return LogMessages.StatusMessages.JobValidationFailed;
    if (!ValidateTotals())
        return LogMessages.StatusMessages.JobValidationFailed;
    if (!ValidateRecordCount())
        return LogMessages.StatusMessages.JobValidationFailed;
    return LogMessages.StatusMessages.JobValidationPassed;
}
public bool Validate()
{
 return LogSuccess(
  new[] {ValidateRecordIdentifiers, ValidateTotals, ValidateRecordCount }
  .All(v=>v()));
}

private bool LogSuccess(bool success)
{
 LogLogic.AddEntry(LogLogic.GetEnumDescription(success
   ? LogMessages.StatusMessages.JobValidationPassed
   : LogMessages.StatusMessages.JobValidationFailed
 );
 return success;
}

值可讀性高於一切(只要它具有相同的效率)。

我唯一要做的更改是消除不需要的變量,並在條件條件下使用函數調用,並替換!。 == false的運算子。 對於視力不好的像我這樣的老齡程序員來說,這更容易看到:)

正如另一位發帖人的評論所暗示的那樣,最好使函數改為InvalidXX,以避免使用否定或== false並提高可讀性。

另外,就將所有條件組合成一個“ AND”語句而言,我會用Lisp而不是c#進行,因為這會使調試和跟蹤變得更加困難。

特別是,您可能不想在每種情況下都輸入相同的錯誤消息-每個情況下都應該使用不同的錯誤消息,以便您確切地了解發生了什么。 將所有個案組合成一個表達式將不允許您執行此操作。


public bool Validate(){

     if (ValidRecordIdentifiers() == false)        { 
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed)); 
        return false; 
    } 

    if (ValidTotals() == false)        { 
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed)); 
        return false; 
    } 

     if (ValidateRecordCount() == false)        { 
        LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationFailed)); 
        return false; 
    } 

    LogLogic.AddEntry(LogLogic.GetEnumDescription(LogMessages.StatusMessages.JobValidationPassed)); 
    return true; 
} 

由於所有條件都相同的聲明,因此您可以在一個條件下進行檢查,然后在下面進行重置作業。

public bool Validate()
{            
    bool validDump;
    if(ValidateRecordIdentifiers() && ValidateTotals() && ValidateRecordCount()) {
        LogLogic.AddEntry(LogLogic.GetEnumDescription(
            LogMessages.StatusMessages.JobValidationPassed));
        return true;
    }

    LogLogic.AddEntry(LogLogic.GetEnumDescription(
        LogMessages.StatusMessages.JobValidationFailed));
    return false;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM