简体   繁体   中英

Using a Switch statement with Enum C#

Hi I am creating a Console app, where the user enters a number of a month and the app works out what month it is and displays answer and displays number of days in the month. I had it working when the switch statements was in the Main method, however now it displays the wrong month. I have the following code:

namespace ConsoleCA2{

public enum Months
{
    January = 31,
    February = 28,
    March = 31,
    April = 30,
    May = 31,
    June = 30,
    July = 31,
    August = 31,
    September = 30,
    October = 31,
    November = 30,
    December = 31
};

public class Program
{
    public const string NEWLINE = "\n";     //constant for new line


    static void Main(string[] args)
    {
        try
        {

            //prompt user for month number.
            Console.Write("Enter a Number to find out what Month it is: ");

            //convert users answer to integer
            int userInput = Convert.ToInt16(Console.ReadLine());

            //declare and initalise
            int daysInMonth = 0;
            string answer = String.Empty;

            //call relevent calculation methods
            answer = DetermineMonth(userInput);
            daysInMonth = DetermineDaysInMonth(userInput);

            //Write users answer to screen
            Console.WriteLine(answer);

            //Prompt user, whether they want to know number of days in the
            //month
            Console.Write("Would you like to know the number of days in" +
                " {0}: ", answer);

            //assign users answer to variable
            string userAnswer = Console.ReadLine();

                //Output answer if needed.
                if (userAnswer == "yes".Trim().ToLower())
                {
                    Console.WriteLine("The number of days in {0} is: {1}", 
                        answer, daysInMonth.ToString());
                }
                else if (userAnswer == "no".Trim().ToLower())
                {
                    Console.WriteLine(NEWLINE);
                    Console.WriteLine("You answered No, Have a good day!");
                }
                else
                {
                    Console.WriteLine("Please answer yes or no.");
                }

            Console.Read(); //Pauses screen for user
        }
            //catch any errors.
        catch (Exception err)
        {
            Console.WriteLine("Error" + err.Message);
        }

    }


    /// <summary>
    /// Determines What month the use enters and returns string value
    /// </summary>
    /// <param name="userInput"></param>
    /// <returns>returns the month as string</returns>
    public static String DetermineMonth(int userInput)
    {
        switch (userInput)
        {
            case 1:
                return Months.January.ToString();
            case 2:
                return Months.February.ToString();
            case 3:
                return Months.March.ToString();
            case 4:
                return Months.April.ToString();
            case 5:
                return Months.May.ToString();
            case 6:
                return Months.June.ToString();
            case 7:
                return Months.July.ToString();
            case 8:
                return Months.August.ToString();
            case 9:
                return Months.September.ToString();
            case 10:
                return Months.October.ToString();
            case 11:
                return Months.November.ToString();
            case 12:
                return Months.December.ToString();
            default:
                return "Error";
        }



    }

    /// <summary>
    /// Determines how many days is in selected month as integer
    /// </summary>
    /// <param name="userInput"></param>
    /// <returns>returns how many days in month</returns>
    public static int DetermineDaysInMonth(int userInput)
    {
        switch (userInput)
        {
            case 1:
                return Convert.ToInt16(Months.January);
            case 2:
                return Convert.ToInt16(Months.February);
            case 3:
                return Convert.ToInt16(Months.March);
            case 4:
                return Convert.ToInt16(Months.April);
            case 5:
                return Convert.ToInt16(Months.May);
            case 6:
                return Convert.ToInt16(Months.June);
            case 7:
                return Convert.ToInt16(Months.July);
            case 8:
                return Convert.ToInt16(Months.August);
            case 9:
                return Convert.ToInt16(Months.September);
            case 10:
                return Convert.ToInt16(Months.October);
            case 11:
                return Convert.ToInt16(Months.November);
            case 12:
                return Convert.ToInt16(Months.December);
            default:
                return 0;
        }
    }

The old switch statement was this:

        switch (userInput)
        {
        case 1:
            answer = Months.January.ToString();
            daysInMonth = Convert.ToInt16(Months.January);
            break;
        case 2:
            answer = Months.February.ToString();
            daysInMonth = Convert.ToInt16(Months.February);
            break;
        case 3:
            answer = Months.March.ToString();
            daysInMonth = Convert.ToInt16(Months.March);
            break;
        case 4:
            answer = Months.April.ToString();
            daysInMonth = Convert.ToInt16(Months.April);
            break;
        case 5:
            answer = Months.May.ToString();
            daysInMonth = Convert.ToInt16(Months.May);
            break;
        case 6:
            answer = Months.June.ToString();
            daysInMonth = Convert.ToInt16(Months.June);
            break;
        case 7:
            answer = Months.July.ToString();
            daysInMonth = Convert.ToInt16(Months.July);
            break;
        case 8:
            answer = Months.August.ToString();
            daysInMonth = Convert.ToInt16(Months.August);
            break;
        case 9:
            answer = Months.September.ToString();
            daysInMonth = Convert.ToInt16(Months.September);
            break;
        case 10:
            answer = Months.October.ToString();
            daysInMonth = Convert.ToInt16(Months.October);
            break;
        case 11:
            answer = Months.November.ToString();
            daysInMonth = Convert.ToInt16(Months.November);
            break;
        case 12:
            answer = Months.December.ToString();
            daysInMonth = Convert.ToInt16(Months.December);
            break;
        default:
            answer = "Error";
            break;
    }

Which worked until I changed to separate methods then it went downhill from there. Now even when I put it back it still gets the months mixed up?

So confused :S

Thank you in advance for any help... if you can understand the messy code :p

NET Framework contains a huge amount of code. Sometime it is just difficult to find the needed one, but the probability that there is something already there are high. And, while it takes time to search, it is a well spent time because you feed yourself with useful knowledge for your future work

CultureInfo.CurrentCulture.DayFormatInfo.MonthNames
DateTime.DaysInMonth

using System.Globalization;
static void Main(string[] args)
{
    Console.Write("Enter a Number to find out what Month it is: ");

    int userInput = Convert.ToInt16(Console.ReadLine());
    if(userInput > 0 && userInput < 13)
    {            
         string monthName = CultureInfo.CurrentCulture.DayTimeFormat.MonthNames[userInput-1];
         int daysInMonth = DateTime.DaysInMonth(2013, userInput);
         ......

    }
}

If you need to account also for leap years you should get input for the year but it is pretty straightforward

That's because your enum has it all mixed up.

There are repetitive values for 31 and 30.

Here is a working example (However there are more ways of optimising it. Like using DateTime class)

public enum Months : int
{
    None = 0,
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12
};

public class Program
{
    public const string NEWLINE = "\n";     //constant for new line

    static void Main(string[] args)
    {
        try
        {
            //prompt user for month number.
            Console.Write("Enter a Number to find out what Month it is: ");

            //convert users answer to integer
            int userInput = Convert.ToInt16(Console.ReadLine());

            //declare and initalise
            int daysInMonth = 0;
            Months answer;

            //call relevent calculation methods
            answer = DetermineMonth(userInput);

            if (answer == Months.None) 
            {
                Console.WriteLine("Please enter a value between 1 and 12");
                return;
            }

            daysInMonth = DetermineDaysInMonth(answer);

            //Write users answer to screen
            Console.WriteLine(answer);

            //Prompt user, whether they want to know number of days in the
            //month
            Console.Write("Would you like to know the number of days in {0}: ", answer);

            //assign users answer to variable
            string userAnswer = Console.ReadLine();

            //Output answer if needed.
            if (userAnswer == "yes".Trim().ToLower())
            {
                Console.WriteLine("The number of days in {0} is: {1}", answer, daysInMonth.ToString());
            }
            else if (userAnswer == "no".Trim().ToLower())
            {
                Console.WriteLine(NEWLINE);
                Console.WriteLine("You answered No, Have a good day!");
            }
            else
                Console.WriteLine("Please answer yes or no.");

            Console.ReadLine(); //Pauses screen for user
        }
        //catch any errors.
        catch (Exception err)
        {
            Console.WriteLine("Error" + err.Message);
        }
    }

    /// <summary>
    /// Determines What month the use enters and returns string value
    /// </summary>
    /// <param name="userInput"></param>
    /// <returns>returns the month as string</returns>
    public static Months DetermineMonth(int userInput)
    {
        switch (userInput)
        {
            case 1:
                return Months.January;
            case 2:
                return Months.February;
            case 3:
                return Months.March;
            case 4:
                return Months.April;
            case 5:
                return Months.May;
            case 6:
                return Months.June;
            case 7:
                return Months.July;
            case 8:
                return Months.August;
            case 9:
                return Months.September;
            case 10:
                return Months.October;
            case 11:
                return Months.November;
            case 12:
                return Months.December;
        }
        return Months.None;
    }

    /// <summary>
    /// Determines how many days is in selected month as integer
    /// </summary>
    /// <param name="userInput"></param>
    /// <returns>returns how many days in month</returns>
    public static int DetermineDaysInMonth(Months userInput)
    {
        switch (Convert.ToInt32(userInput))
        {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                return 31;
            case 2:
                return 28;
            case 4:
            case 6:
            case 9:
            case 11:
                return 30;
        }
        return 0;
    }
}

You use an enum to create symbolic names for constants. That's not what you want in this case.

I think what you want is a lookup table that, given a value A, returns a value B. In your case, you can use a couple of arrays:

string[] monthNames = new string[]
{
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "November", "December"
};
int[] monthDays = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

And you can then get a month name and the number of days with a lookup:

int userInput = Convert.ToInt16(Console.ReadLine());
if (userInput < 1 || userInput > 12)
    Console.WriteLine("Error: invalid month.");
else
{
    answer = monthNames[userInput-1];
    daysInMonth = monthDays[userInput-1];
}

There are other ways to do this, including using structs or classes for the months and days, but those are slightly more advanced topics.

In addition, .NET has a DateTime structure that has all these capabilities and more for working with dates and times. In a production program, you'd use that rather than rolling your own.

You might want to consider simplifying this a bit and making your enum numbers match the number of the month. Then store the days in that month elsewhere.

Then you could do (Months)userInput to get the enum and eliminate at least one of the switch statements.

You could store the days in each month with a Dictionary, or some other way, as long as the enum stores a unique int for each value.

This is not how you use enums.

They are not just static key value pairs: if they were, you could use more than just integral types. No, they aren't much more than typesafe wrappers around integral types.

The problem with yours is this:

public enum Months
{
    January = 31,
    February = 28,
    March = 31,
    April = 30,
    May = 31,
    June = 30,
    July = 31,
    August = 31,
    September = 30,
    October = 31,
    November = 30,
    December = 31
};

This means that, as far as the CLR knows, January, March, May, July, August, October and December are exactly the same . Same deal with April, June, September and November.

The correct way to do this would be like this:

public enum Months
{
    None = -1,
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12
};

And then your DetermineMonth method would just be this:

public static Months DetermineMonth(int userInput)
{
    Months temp = (Months)userInput;
    return Enum.IsDefined(typeof(Months), temp) ? temp : Months.None; 
}

And then the DetermineDaysInMonth would be this:

public static int DetermineDaysInMonth(int userInput)
{
    if (!((Months[])Enum.GetValues(typeof(Months))).Contains((Months)userInput)
        return 0;
    else return DateTime.DaysInMonth(DateTime.Today.Year, userInput);
}

You can have Extension method on your enum to return number of days -

public enum Months
{
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
}

public static class MonthsExtensions
{
    public static int DaysInMonths(this Months month)
    {
        switch (month)
        {
            case Months.January:
            case Months.March:
            case Months.May:
            case Months.July:
            case Months.August:
            case Months.October:
            case Months.December:
                return 31;

            case Months.April:
            case Months.June:
            case Months.September:
            case Months.November:
                return 30;

            case Months.February:
                return 28;
        }
        return 0;
    }

You can then get number of days like this -

int daysInMonths = Months.January.DaysInMonths();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM