[英]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.