c# check for datetime not working [closed]

2019-09-22 10:58发布

问题:

I am creating my own DateTime class within C# and for some reason my checks are not working. When I run the program and enter a date it always stops and reaches the last line which is on the "Day" method and says "ArgumentOutOfException. Is there anyway to solve this issue and to make my checks called "Value" working?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace date
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("\t\t\t\t\t\tNextDate Application\n\t\t\t\t\t-------------------------------------");

            Console.WriteLine("please enter date as dd/MM/yyyy");
            int day;
            int month;
            int year;

            string[] read = Console.ReadLine().Split('/');
            day = int.Parse(read[0]);
            month = int.Parse(read[1]);
            year = int.Parse(read[2]);

            Date date = new Date(day, month, year);
            Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year);
            Console.ReadLine();
        }

        class Date
        {
            private int _month; // 1-12
            private int _day; // 1-31 depending on month
            private int _year;

            public Date(int day, int month, int year)
            {
                Day = day;
                Month = month;
                Year = year;
            }

            public int Year
            {
                get { return _year; }
                set
                {
                    if (value >= 1820 && value <= 2020)
                        _year = value;
                    else
                        throw new ArgumentOutOfRangeException("year", value, "year out of range");
                }
            }

            public int Month
            {
                get { return _month; }
                set
                {
                    if (value > 0 && value <= 12)
                        _month = value;
                    else
                        throw new ArgumentOutOfRangeException("Month", value, "Month must be 1-12");
                }
            }

            public int Day
            {
                get { return _day; }
                set
                {

                    int[] days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

                    if (value > 0 && value <= days[_month])
                        _day = value;

                    else if (_month == 2 && value == 29 &&
                        _year % 400 == 0 || (_year % 4 == 0 && _year % 100 != 0))
                        _day = value;
                    else
                    throw new ArgumentOutOfRangeException("Day", value, "Day is out of range");



                }

            }
        }
    }
}

回答1:

The first thing you do in your constructor is set the Day property:

public Date(int day, int month, int year)
{
    Day = day;
    Month = month;
    Year = year;
}

What does that setter do? A lot, it seems. Specifically, first it checks this:

if (value > 0 && value <= days[_month])

For your given input (in a comment above), value is 3. 3 > 0 is true, so that's ok. But 3 is not <= 0. And days[_month] is 0 at this time. So this condition is false.

Your next condition is:

else if (_month == 2 && value == 29 &&

This is also false, since _month is currently 0 (and value is 3).

So then what does your method do? This:

throw new ArgumentOutOfRangeException("Day", value, "Day is out of range");

Which explains why you're getting an ArgumentOutOfRangeException. When you throw an exception, that exception is, well, thrown.


It seems like you want to set Day last in your constructor:

public Date(int day, int month, int year)
{
    Year = year;
    Month = month;
    Day = day;
}

Though having so much hidden dependencies between your values probably should be addressed at a higher logical level as well.



回答2:

In your constructor:

public Date(int day, int month, int year) {
  Day = day;
  Month = month;
  Year = year;
}

you assigned the Day property first. At this point Month will be default initialised – to zero – but the checks in the Day setter assume Month has been set. So the days in the month value will be 0.

You need to rethink how you do this. Probably better is to not use automatic properties so you can set the fields and then validate the date as a whole.

Reserve setters and validation there to the external interface.

Even better would be to make it an imutable value type.

Better still would be to not re-invent the wheel (unless you have very good reason).



回答3:

Date constructor using _month before assign. Assign Month before Day. You need to change Date constructor as follows.

public Date(int day, int month, int year)
{
   Month = month;             
   Day = day;
   Year = year;
}