0

I recently asked this question: https://stackoverflow.com/questions/48582699/equality-for-a-dateofbirth-value-object. I am going to avoid a DateOfBirth value object. Instead I am planning to use a type alias. I have a few options with regards to my constructor:

Option 1

using DateOfBirth=System.DateTime;
DateOfBirth DateOfBirth;    

public Person (DateOfBirth dateOfBirth)
{
     if (dateOfBirth.TimeOfDay.TotalSeconds > 0)
         throw new ArgumentException("Date of birth cannot contain a time.")
     DateOfBirth = dateOfBirth;
}

Option 2

DateOfBirth DateOfBirth;   
public Person(int day, int month, int year)
{
   //Validation to make sure day, month and year are valid.
   DateOfBirth = new DateOfBirth(year,month,day);
}

I am trying to decides, which option to choose. The validation for option two could be quite complex because some months have different number of days. Therefore I am hoping that option one is suitable for this.

Also, should I be using type aliases in my Unit Tests or just refer to them as the primitive type i.e. date time?

4

Your option one is a bad idea. If you are using a DateTime, call it a DateTime.

public Person (DateTime dateOfBirth)

is very clear, whereas your variant with a using is cryptic.

If you want to be able to have business rules specific to a date of birth (which is reasonable, given that many DateTime values won't necessarily be valid birth dates), your best option could be to inherit from DateTime. Unfortunately, you won't be able to do it, since DateTime is a struct.

Therefore, create your own class, and put a DateTime field inside it. Implementing comparisons in this case is pretty straightforward, since you can delegate all the work to the underlying DateTime. You still need to handle == and Equals.

Inside this class, you'll be able to do input validation (within the constructor), to extract the data you need (i.e. keep the date and drop the time), and well as ensure that the callers can only get the information they need, and never be able to access the underlying DateTime field.

10
  • Wouldn't I have to handle all comparisons eg <, >, <=, >= etc.
    – w0051977
    Feb 3 '18 at 16:52
  • That depends entirely on your needs. Are you going to compare dates of birth quite often in the source? (Validations aside)
    – Laiv
    Feb 3 '18 at 17:44
  • @Laiv, yes I am. For example, the domain logic has to assess what age category the Person is in e.g. under 18, 18-35, 35-50 etc.
    – w0051977
    Feb 3 '18 at 19:50
  • 1
    Those are age ranges, not dates of birth :-). Basically, you only need to perform the next operation todayDate - dateOfBirth. But not comparisons between dates. In other words, the next statement is semantically wrong dateOfbirth is between 35 and 50.
    – Laiv
    Feb 3 '18 at 19:53
  • 1
    @Laiv, I don't understand what you mean. Could you clarify? Perhaps in an answer? I do this: If DateOfBirth < DateTime.Now.AddYears(-18). This will tell me if the person is under 18
    – w0051977
    Feb 3 '18 at 20:24
2

I think there are another option. As you feel the concept of date without time component has merit for your domain, then what is important here is that the validation happens as soon as you have the date, rather than waiting for validation inside the Person constructor. To do this you would use a simple wrapper class as follows:

class DateOnly {
    public readonly DateTime Value;
    public DateOnly ( DateTime value ) {
       if ( value.Date != value )
           throw new IllegalArgumentException ( "time component not allowed" );
       Value = value;
    }
    public DateOnly ( int year, int month, int day ) {
        Value = new DateTime ( year, month, day );
    }
}


class Person {
     Person ( DateOnly birthDate ) { }
}
16
  • and as @Arseni says, don't forget == and Equals...
    – Erik Eidt
    Feb 3 '18 at 16:01
  • Wouldn't I have to handle all nine equality operators? Eg <, >, <=, >= etc,
    – w0051977
    Feb 3 '18 at 16:50
  • No, unless you want to do relations on DateOnly. Since you can always access the underlying DateTime Value, you can do your other comparisons on that directly. The reason to handle the == and Equals is so your class DateOnly works nicely with hash tables and such.
    – Erik Eidt
    Feb 3 '18 at 17:32
  • Please see my question here and specifically the comments under the last answer: codereview.stackexchange.com/questions/186590/…
    – w0051977
    Feb 3 '18 at 17:43
  • The answerer seems to think that you should not access the encapsulated value directly. What do you think.
    – w0051977
    Feb 3 '18 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.