views:

69

answers:

5

A sample class in "C# Class Desing Handbook" (pg 137) does not call the classes validation method for a specific field from inside the classes only constructor. So basically the sample class allows you to create an object with bad data and only throws an error for that data when you call the field's property which does validation on it then. So you now have a bad object and don't it know until after the fact.

I never understood why they don't just call the property from the constructor thus throwing an error immediately if bad data is found during initialization? I've emailed them to no avail...

I tend to use the following format by calling my properties from my constructors - is this proper structure to validate initialization data? ty

class Foo
{
    private string _emailAddress;

    public Foo(string emailAddress)
    {
        EmailAddress = emailAddress;
    }

    public string EmailAddress
    {
        get { return _emailAddress; }
        set
        {
            if (!ValidEmail(value))
                throw new ArgumentException
                    (string.Format
                    ("Email address {0} is in wrong format", 
                    value));

            _emailAddress = value;
        }
    }


    private static bool ValidEmail(string emailAddress)
    {
        return Regex.IsMatch
            (emailAddress, @"\b[A-Z0-9._%+-]+" +
                           @"@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
                           RegexOptions.IgnoreCase);
    }
}
+1  A: 

Well, for one, you are likely to get the dreaded NullReferenceException, since you are not checking if emailAddress is null at any level. That particular check should be done in the constructor itself, and if emailAddress IS null, throw an ArgumentNullException. As for the rest, I don't see any particular problems with it as it is written in your sample. However, there are some issues that may arise if you make the property virtual, and derive children from this class. Execution order of field initialization, base and derived class consturctors then becomes an issue, and you have to be careful.

jrista
I left it out for clarity but yes thanks...
You're welcome. :)
jrista
A: 

I see nothing wrong with this approach. You can call methods on this within the constructor, and property setters/getters are just syntactic sugar for method calls.

Kevlar
The class behaves differently if the email address is set in the constructor vs. through the property setter. Inconsistent behavior is not a good design property :-)
Eric J.
in the example code the asker provided the constructor uses the property setter as far as i can tell, so the behavior would in fact be consistent. Is there something i'm missing?
Kevlar
+1  A: 

Yes, if your general approach is:

Ensure that you can only get an instance of a valid object

then I love it.

Constructors should be used to create objects that are immediately valid, not to create just a 'container', for things to be put in.

Noon Silk
Yes getting only valid objects is the idea here - I add overloads of the constructor to allow users to enter a blank field where it's ok to do so. ty.
A: 

the validation is happening when the Email address is set. This is where you want it because the email address could potentially be set again later.

If you also called validation in the constructor, you'd be making an extra, redundant validation call (once when constructed, another when the email address is set in the constructor).

free-dom
Huh? The original setting of the email address is in the constructor which calls _emails' property. If I just set _email directly then I would have a bad object if a bad email was passed in. It would only be validated if the property was changed after the object was instantiated.
The constructor is invoking the setter of the Property: "EmailAddress"
free-dom
Yes I understand - I wrote it. What I didn't understand was you comment... sorry.
I think you missed the point of my question. The sample in the book just sets the field directly with no validation whatsoever but does validate the the field and throws an error when accessing the property after the object is created...
btw... when I say set the field directly I mean in the constructor.
+1  A: 

It makes no sense to me not to validate data in the constructor. As you point out, the object can end up in an invalid state. Given this design, you would not even realize that you had bad data when calling the getter.

For anything of moderate complexity or higher, I tend to use a Broken Rules approach rather than immediately throwing an Exception. In that approach, I define a BrokenRules object that contains information about the class and property that is invalid, and the reason that it is invalid. Then, in a common base class, I define a List to hold a list of everything "wrong" about the object. A property (again in the base class) IsValid indicates whether there are presently any broken rules.

The advantage of this is that there could potentially be several things wrong with the object state. If a user is being asked to correct the problems (i.e. this object is set from a UI), providing a list of all problems lets the user correct them in one go, rather than fixing one error just to be told there is another one. And another one. Etc.

Eric J.
Thanks Eric - I'll look into the Broken Rules approach! Just starting to build frameworks and still learning. Picked up 'Framework Design Guidelines' which I'm having a blast with! Great book.