2013-09-28 89 views
1

我閱讀了幾篇關於異常處理良好實踐的文章。它大多解決了作者期待的意外例外。我只想澄清並消除我可能做的可能的不良做法。由於我已經預料到這些問題已經發生,所以我認爲拋出異常有點多餘。處理預期異常

比方說,我有這樣的代碼:

string fileName = Path.Combine(Application.StartupPath, "sometextfile.txt"); 

// There's a possibility that the file doesn't exist <<<<<<<<<<<<<<<<<<<<< 
if (!File.Exists(fileName)) 
{ 
    // Do something here 
    return; 
} 

// Therefore, this will return an exception 
using (StreamReader file = 
    new StreamReader(fileName)) 
{ 
    // Some code here 
} 

當然,我會做的是有一個消息說「找不到文件」通知用戶。有沒有這樣做的有效或更好的方法?

另一個想法我已經是創造一個枚舉其中包含預期的錯誤代碼,然後創建一個將調用一個消息框顯示該具體情況的錯誤消息的方法:

enum ErrorCodes {null, zero, ...} 
public void showError(ErrorCodes error) 
{ 
    string message; 
    switch (error) 
     { 
     case ErrorCode.null: 
     { 
      message = "value cannot be null"; 
      break; 
     } 
     case ErrorCode.zero: 
     { 
      message = "cannot divide by zero"; 
      break; 
     } 
} 

MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); 
} 
+4

這是一個*真的*不好主意。你已經得到一個體面的異常消息,沒有這個代碼。只需捕捉StreamReader構造函數拋出並顯示其Message屬性的異常即可。 –

+1

是的,我明白,但我想展示一個用戶可以輕鬆理解的自定義消息,避免異常而不是更好地抓住它? – CudoX

+0

您應該將消息呈現與io訪問分開。也許你的代碼有一天會在控制檯應用程序中使用?順便說一句,只使用意外的執行路徑的異常,而不是像不存在的文件。 –

回答

1

如果代碼即試圖訪問該文件位於前端,例如用於點擊的事件處理程序,則可以檢查錯誤情況,顯示消息並返回。

如果我正確理解你的問題,你想知道你是否應該這樣做:

public void button_Click() { 
    if(!File.Exists(textBox.Text)) { 
     MessageBox.Show("Could not find the file"); 
     return; 
    } 

    ProcessFile(textBox.Text); // would have thrown an exception if the file didn't exist 
} 

這將是罰款,除非ProcessFile拋出任何其他類型的異常也不會被處理。

你可以這樣做:

public void button_Click() { 
    try { 
     ProcessFile(textBox.Text); // throwns an exception if the file didn't exist 
    } catch(Exception ex) { 
     MessageBox.Show(GetUserMessage(ex)); 
     return; 
    } 
} 

在我看來這是更好地做到既:

public void button_Click() { 
    try { 
     if(!File.Exists(textBox.Text)) { 
      MessageBox.Show("Could not find the file"); 
      return; 
     } 

     ProcessFile(textBox.Text); // throwns an exception if the file didn't exist 
    } catch(Exception ex) { 
     MessageBox.Show(GetUserMessage(ex)); 
     return; 
    } 
} 

這種方式可以提供最具體的消息,與用戶相關的他在做什麼在此刻。例如,如果他試圖打開Excel文件,可以說「找不到想要導入的Excel文件」。

這也適用於在您檢查的點與您嘗試處理文件的位置之間刪除或重命名文件的情況。

另外,您可以完成此類似:

public void button_Click() { 
    try { 
     if(!File.Exists(textBox.Text)) { 
      throw new UserException("Could not find the file"); 
     } 

     ProcessFile(textBox.Text); // throwns an exception if the file didn't exist 
    } catch(Exception ex) { 
     MessageBox.Show(GetUserMessage(ex)); 
     return; 
    } 
} 

在這種情況下,你會創建自己的Exception類UserException,只是沿着傳遞消息,而無需轉換它。這將允許您重複使用您用來顯示消息的相同代碼。

例外類

如果在一些類庫時出現錯誤,那麼你應該拋出異常。例外的目的是不能忽視錯誤。

例如,你不應該這樣想:

class MyFileHandler { 
    public void OpenFile(string fileName) { 
     if(!File.Exists(fileName)) return; 
     // do stuff 
    } 

    public void DoStuff() { 
     // do stuff 
    } 
} 

現在,如果一個開發者稱爲myFileHandlerInstance.OpenFile("note.txt"),他會認爲它的工作。你可以返回一個布爾值,像這樣:

class MyFileHandler { 
    public bool OpenFile(string fileName) { 
     if(!File.Exists(fileName)) return false; 
     // do stuff 
     return true; 
    } 

    public void DoStuff() { 
     // do stuff 
    } 
} 

但現在你是依靠開發者檢查值,這曾經是一個常用的方法,但誤差得到了忽略,忽視這就是爲什麼例外成爲更好的做法。至於要顯示給用戶的內容,你實際上不應該直接顯示異常消息,這些消息是針對開發者而不是用戶的。我建議採取一個異常對象,並返回最佳的消息,像這樣的方法:

public string GetUserErrorMessage(Exception ex) { 
    if(ex is FileLoadException) { 
     var fileLoadException = (FileLoadException)ex; 
     return "Sorry but we failed to load the file: " + fileLoadException.FileName; 
    } 
} 

您可以檢查異常屬性的細節,包括錯誤代碼,如果你喜歡。此外,我建議在某處爲您自己的調試目的捕獲實際的異常詳細信息,這些地方對用戶不可見。

+0

感謝您的建議,我只是想澄清一下 - 如果我已經檢查了有關異常的細節,該怎麼辦?將它包裝在try-catch語句並捕獲它的異常細節而不是跳轉到「用戶 - 消息框」(因爲開發人員已經檢測到的異常__已被預期)是否明智呢? – CudoX

+0

@Gelo103097我不是當然,我理解你的問題,但我更新了我的迴應,試圖回答它。 –

1

這些事情從來都不容易。根據定義,一個例外是(像西班牙宗教裁判所)從未預料到的。在第一個示例中,當您調用File.Exist時,該文件可能存在,但當您嘗試打開文件時文件不存在(文件被刪除,網絡失敗,拔出拇指驅動器等)。就最佳做法而言:儘可能保護自己,只抓住你知道如何處理和希望得到最好的例外。程序將會失敗,你所能做的最好的事情就是確保未處理的故障儘可能清楚地傳遞給代碼用戶(第二個例子的核心)。

通信故障很大程度上取決於代碼的作用以及誰在使用它。消息框經常被使用,但通常並不「有用」,因爲如果錯誤的原因不清楚,用戶可以做的唯一的事情就是發送一個jpg圖像(這是最好的情況:-D)。提供記錄問題的方法和/或允許用戶剪切/粘貼信息的自定義對話框(如堆棧跟蹤)更加有用。考慮用戶選擇文件並存在網絡呃逆的情況。他們告訴你他們得到了這個文件沒有找到的錯誤,但是當你或他們看到它時,因爲那時網絡正常工作。一個簡單的「找不到文件」的消息會給你足夠的信息,所以你必須告訴用戶「我不知道,現在很高興它現在可用」......這並不能激發你的信心。這裏的最佳做法是讓自己足夠的「麪包屑」,至少對發生的事情有一個粗略的想法。即使有一個完整的文件路徑可以給你線索,你需要弄清楚出了什麼問題。