Exception handling: how granular would you go when it comes to argument validation?

旧街凉风 提交于 2019-12-06 12:20:20

问题


I'm coding a simple little class with a single method send an email. My goal is to implement it in a legacy Visual Basic 6 project, exposing it as a COM object via the COM Interop facility.

There's a detail I'm finding difficult to resolve, that being how granular should I be at validating parameters. On that light, a thing I'm really not happy about, and which is not a detail at all, is the way I'm actually handling exceptions:

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(@"(\w+@[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
}

Any suggestion will be much appreciated, so thanks much in advance for all your comments!

Note: Would it be convenient to implement Enterprise Library's Validation Application Block on this particular case?


回答1:


Consider the contract that you are imposing upon the callers of SendMail. They are required to pass you a "valid email address". Who decides what is valid? SendMail does. Basically your method is "high maintenance" -- it wants things exactly the way it likes, and the only way to tell whether what you're going to give it will be satisfactory is to try and hope for the best.

Don't write high-maintenance methods without giving the caller a chance to know how to satisfy it, or at least have a way to avoid the exception. Extract the validation logic to an "IsValidAddress" method that returns a Boolean. Then have your SendMail method call IsValidAddress and throw if it is invalid.

You get several nice effects from this change:

(1) Increased separation of concerns. SendMail's job is to make the email mechanism work, not to pass judgment on whether an email address is valid. Isolate that policy decision to code that specializes in verification.

(2) Address validation is a useful tool in of itself; there are lots of times when you want to know whether an address is well-formed without sending mail to it.

(3) You can update and improve your validation logic easily because it is all in one sensible place.

(4) Callers have a way that they can guarantee that no exception will be thrown. If a caller cannot call a method without guaranteeing that the arguments are valid, then they have to catch the exception. Ideally you should never make a caller have to handle an exception to make their code correct; there should be a way they can write correct code that never throws, even if the data they've been handed is bad.

Here are a couple of articles I've written on this subject that you might find helpful:

Exception handling: http://ericlippert.com/2008/09/10/vexing-exceptions/

High-maintenance methods: http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx




回答2:


Having two throw statements in a row makes no sence - only the first one will be executed and then control will be passed to the exception handler and never to the second throw.

In my opinion it is more than enough to just say smth like "Sender e-mail is invalid." An e-mail is quite simple and short and so the user will be able to resolve this without any additional guidance.

I also think it would be better to first check all the passed in values and only then start work. What's the point in partially doing work if you can then encounter an invalid parameter value and throw an exception and never complete this work. Try to indicate errors as early as you can - at the very beginning if possible.




回答3:


And:

Use

string.IsNullOrEmpty(subject)

rather than

subject == null

for checking if your strings are empty.



来源:https://stackoverflow.com/questions/1102030/exception-handling-how-granular-would-you-go-when-it-comes-to-argument-validati

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!