2009-07-09 42 views
1

我使用單一方法編寫簡單的小類,發送電子郵件。我的目標是在傳統的Visual Basic 6項目中實現它,通過COM Interop工具將其作爲COM對象公開。異常處理:當涉及到參數驗證時,您將如何精細化?

我發現有一個細節難以解決,那就是我應該在驗證參數時應該如何精細化。在光,我真的不開心,和一個東西是不是一個細節都被我其實異常處理的方式:

public class MyMailerClass 
{ 
    #region Creation 
    public void SendMail(string from, string subject, string to, string body) 
    { 
     if (this.IsValidMessage(from, subject, to, body)) // CS1501 
     { 
      MailMessage msg = new MailMessage(); 
      msg.IsBodyHtml = true; 
      msg.From = new MailAddress(from); 
      msg.To.Add(to); 
      msg.Subject = subject; 
      msg.Body = body; 
      SmtpClient srv = new SmtpClient("SOME-SMTP-HOST.COM"); 
      srv.Send(msg); 
     } 
     else 
     { 
      throw new ApplicationException("Invalid message format."); 
     } 
    } 
    #endregion Creation 

    #region Validation 
    private bool IsValidMessage(string from, string subject, string to, string body) 
    { 
     Regex chk = new Regex(@"(\[email protected][a-zA-Z_]+?\.[a-zA-Z]{2,6})"); 
     if (!chk.IsMatch(from)) 
     { 
      return false; 
     } 
     if (!chk.IsMatch(to)) 
     { 
      return false; 
     } 
     if (!string.IsNullOrEmpty(subject)) 
     { 
      return false; 
     } 
     if (!string.IsNullOrEmpty(body)) 
     { 
      return false; 
     } 
     else 
     { 
      return true; 
     } 
    } 
    #endregion Validation 
} 

任何建議將非常感激,所以非常感謝爲您的所有意見!

注意:在這個特殊情況下實現企業圖書館的Validation Application Block會方便嗎?

+0

作爲一個側面說明,你'使用ArgumentException錯誤 - 第二個參數是一個_string_,它應該是無效參數的_name_。相反,你在那裏傳遞參數的價值。你應該這樣做:拋出新的ArgumentException(「無效的發件人地址:」+ from,「from」);` – 2009-07-09 06:11:06

+0

非常感謝Pavel,我添加了它! – 2009-07-09 06:36:54

+0

新版本的代碼將很難調試。在IsValidMessage()中,你檢查一行中的所有條件。如何在調試器中執行代碼時找出哪一個不滿意?你可以這樣寫:if(string.IsNullOrEmpty(subject)){return false; } if(!string.IsNullOrEmpty(body)){return false; }然後創建一個Regex對象,並再次檢查一個條件,一旦條件不滿足,立即返回false。 – sharptooth 2009-07-09 08:13:45

回答

9

考慮您施加給SendMail調用者的合同。他們必須向您傳遞「有效的電子郵件地址」。誰決定什麼是有效的? SendMail的確如此。基本上你的方法是「高維護」 - 它想要的東西完全是它喜歡的方式,而唯一能告訴你是否要給它滿意的方法就是盡力而爲,並希望最好。

不要編寫高維護方法,不要給調用者一個機會知道如何去滿足它,或者至少有辦法避免這個異常。將驗證邏輯提取到返回布爾值的「IsValidAddress」方法。然後讓你的SendMail方法調用IsValidAddress並拋出它是否無效。

你從這種變化幾個不錯的效果:

(1)的擔憂加劇分離。 SendMail的工作是使電子郵件機制起作用,而不是判斷電子郵件地址是否有效。將該政策決策隔離爲專門用於驗證的代碼。

(2)地址驗證本身是一個有用的工具;有很多時候你想知道一個地址是否形成良好而不發送郵件。 (3)您可以輕鬆地更新和改進驗證邏輯,因爲它全部在一個明智的地方。

(4)調用者有一種方法可以保證不會拋出異常。如果調用者不能在不保證參數有效的情況下調用方法,那麼他們必須捕獲異常。理想情況下,你永遠不應該讓調用者必須處理異常,以使他們的代碼正確;應該有一種方法可以編寫永不丟失的正確代碼,即使他們交給的數據不好。

這裏有幾篇文章我寫關於這個問題,你可能會發現有用:

異常處理:http://ericlippert.com/2008/09/10/vexing-exceptions/

高保養方法:http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx

3

在一行中有兩個throw語句沒有意義 - 只有第一個語句會被執行,然後控制權將被傳遞給異常處理程序,而不會傳遞給第二個throw

在我看來,僅僅說出像「發件人電子郵件無效」這樣的綽綽有餘。電子郵件非常簡單,所以用戶無需任何額外的指導即可解決此問題。

我也認爲最好先檢查所有傳入的值,然後才能開始工作。如果你可以遇到一個無效的參數值並拋出一個異常,並且永遠不會完成這項工作,那麼在部分工作中有什麼意義。儘可能早地指出錯誤 - 儘可能在一開始就指出錯誤。

+0

所以,你的意思是像在三元方式檢查方法一開始時每個參數的有效性,或者以「isMsgOk = true」的形式攜帶布爾標誌到最後,然後完成所有的構成那裏? – 2009-07-09 06:44:37

1

和:

使用

string.IsNullOrEmpty(subject) 

而不是

subject == null 

的,如果你的字符串是空的檢查。