我想重构一个方法的mumbo jumbo以使其更易读,它可以根据我的喜好使用许多嵌套的IF。
你会如何重构这个?
public static void HandleUploadedFile(string filename)
{
try
{
if(IsValidFileFormat(filename)
{
int folderID = GetFolderIDFromFilename(filename);
if(folderID > 0)
{
if(HasNoViruses(filename)
{
if(VerifyFileSize(filename)
{
// file is OK
MoveToSafeFolder(filename);
}
else
{
DeleteFile(filename);
LogError("file size invalid");
}
}
else
{
DeleteFile(filename);
LogError("failed virus test");
}
}
else
{
DeleteFile(filename);
LogError("invalid folder ID");
}
}
else
{
DeleteFile(filename);
LogError("invalid file format");
}
}
catch (Exception ex)
{
LogError("unknown error", ex.Message);
}
finally
{
// do some things
}
}
答案 0 :(得分:24)
我会将测试中的条件反转为如果不好然后deleteAndLog ,如下例所示。这样可以防止嵌套并将操作置于测试附近。
try{
if(IsValidFileFormat(filename) == false){
DeleteFile(filename);
LogError("invalid file format");
return;
}
int folderID = GetFolderIDFromFilename(filename);
if(folderID <= 0){
DeleteFile(filename);
LogError("invalid folder ID");
return;
}
...
}...
答案 1 :(得分:10)
守卫条款。
对于每个条件,否定它,将else块更改为then块,然后返回。
因此
if(IsValidFileFormat(filename)
{
// then
}
else
{
// else
}
成为:
if(!IsValidFileFormat(filename)
{
// else
return;
}
// then
答案 2 :(得分:2)
如果您不反对使用例外,则可以在不嵌套的情况下处理检查。
警告,未来的航空代码:
public static void HandleUploadedFile(string filename)
{
try
{
int folderID = GetFolderIDFromFilename(filename);
if (folderID == 0)
throw new InvalidFolderException("invalid folder ID");
if (!IsValidFileFormat(filename))
throw new InvalidFileException("invalid file format!");
if (!HasNoViruses(filename))
throw new VirusFoundException("failed virus test!");
if (!VerifyFileSize(filename))
throw new InvalidFileSizeException("file size invalid");
// file is OK
MoveToSafeFolder(filename);
}
catch (Exception ex)
{
DeleteFile(filename);
LogError(ex.message);
}
finally
{
// do some things
}
}
答案 3 :(得分:1)
一种可能的方法是使用单个if语句来检查条件何时为真。每个检查都有一个回报。这会将您的方法转换为“if”块而不是嵌套。
答案 4 :(得分:1)
这里重构的次数不多,因为由于错误消息与执行的测试有关,因此分别保留3个测试。您可以选择让测试方法报告错误以便记录,这样您就不会在if / else树中使用它们,这可能会使事情更简单,因为您可以简单地测试错误并记录它+删除文件。
答案 5 :(得分:1)
在David Waters的回复中,我不喜欢重复的DeleteFile LogError模式。我会编写一个名为DeleteFileAndLog的帮助方法(字符串文件,字符串错误),或者我会编写如下代码:
public static void HandleUploadedFile(string filename)
{
try
{
string errorMessage = TestForInvalidFile(filename);
if (errorMessage != null)
{
LogError(errorMessage);
DeleteFile(filename);
}
else
{
MoveToSafeFolder(filename);
}
}
catch (Exception err)
{
LogError(err.Message);
DeleteFile(filename);
}
finally { /* */ }
}
private static string TestForInvalidFile(filename)
{
if (!IsValidFormat(filename))
return "invalid file format.";
if (!IsValidFolder(filename))
return "invalid folder.";
if (!IsVirusFree(filename))
return "has viruses";
if (!IsValidSize(filename))
return "invalid size.";
// ... etc ...
return null;
}
答案 6 :(得分:0)
上面的精灵让我大开眼界。这是一个替代方案,位于try {}
中你可以通过在MoveToSafeFolder之后返回来缩短它(即使你正在返回finally块也会被执行。)那么你不需要为errorMessage分配一个空字符串,而你不需要检查在删除文件并记录消息之前,errorString为空。我没有在这里做,因为很多人发现早期的回报令人反感,我在这个例子中同意,因为在返回对许多人来说不直观的情况下执行finally块。
希望这有帮助
string errorMessage = "invalid file format";
if (IsValidFileFormat(filename))
{
errorMessage = "invalid folder ID";
int folderID = GetFolderIDFromFilename(filename);
if (folderID > 0)
{
errorMessage = "failed virus test";
if (HasNoViruses(filename))
{
errorMessage = "file size invalid";
if (VerifyFileSize(filename))
{
// file is OK
MoveToSafeFolder(filename);
errorMessage = "";
}
}
}
}
if (!string.IsNullOrEmpty(errorMessage))
{
DeleteFile(filename);
LogError(errorMessage);
}
答案 7 :(得分:0)
我会这样:
public enum FileStates {
MoveToSafeFolder = 1,
InvalidFileSize = 2,
FailedVirusTest = 3,
InvalidFolderID = 4,
InvalidFileFormat = 5,
}
public static void HandleUploadedFile(string filename) {
try {
switch (Handledoc(filename)) {
case FileStates.FailedVirusTest:
deletefile(filename);
logerror("Virus");
break;
case FileStates.InvalidFileFormat:
deletefile(filename);
logerror("Invalid File format");
break;
case FileStates.InvalidFileSize:
deletefile(filename);
logerror("Invalid File Size");
break;
case FileStates.InvalidFolderID:
deletefile(filename);
logerror("Invalid Folder ID");
break;
case FileStates.MoveToSafeFolder:
MoveToSafeFolder(filename);
break;
}
}
catch (Exception ex) {
logerror("unknown error", ex.Message);
}
}
private static FileStates Handledoc(string filename) {
if (isvalidfileformat(filename)) {
return FileStates.InvalidFileFormat;
}
if ((getfolderidfromfilename(filename) <= 0)) {
return FileStates.InvalidFolderID;
}
if ((HasNoViruses(filename) == false)) {
return FileStates.FailedVirusTest;
}
if ((VerifyFileSize(filename) == false)) {
return FileStates.InvalidFileSize;
}
return FileStates.MoveToSafeFolder;
}
答案 8 :(得分:0)
这个怎么样?
public static void HandleUploadedFile(string filename)
{
try
{
if(!IsValidFileFormat(filename))
{ DeleteAndLog(filename, "invalid file format"); return; }
if(GetFolderIDFromFilename(filename)==0)
{ DeleteAndLog(filename, "invalid folder ID"); return; }
if(!HasNoViruses(filename))
{ DeleteAndLog(filename, "failed virus test"); return; }
if(!!VerifyFileSize(filename))
{ DeleteAndLog(filename, "file size invalid"); return; }
// --------------------------------------------------------
MoveToSafeFolder(filename);
}
catch (Exception ex) { LogError("unknown error", ex.Message); throw; }
finally { // do some things }
}
private void DeleteAndLog(string fileName, string logMessage)
{
DeleteFile(fileName);
LogError(logMessage));
}
或者,甚至更好,......这个:
public static void HandleUploadedFile(string filename)
{
try
{
if(ValidateUploadedFile(filename))
MoveToSafeFolder(filename);
}
catch (Exception ex) { LogError("unknown error", ex.Message); throw; }
finally { // do some things }
}
private bool ValidateUploadedFile(string fileName)
{
if(!IsValidFileFormat(filename))
{ DeleteAndLog(filename, "invalid file format"); return false; }
if(GetFolderIDFromFilename(filename)==0)
{ DeleteAndLog(filename, "invalid folder ID"); return false; }
if(!HasNoViruses(filename))
{ DeleteAndLog(filename, "failed virus test"); return false; }
if(!!VerifyFileSize(filename))
{ DeleteAndLog(filename, "file size invalid"); return false; }
// ---------------------------------------------------------------
return true;
}
private void DeleteAndLog(string fileName, string logMessage)
{
DeleteFile(fileName);
LogError(logMessage));
}
注意:你不应该在没有重新抛出它的情况下捕获和吞咽通用异常......