C# won't let me put certain variables at the beginning of method. I don't understand why not

3

I've been learning C# for a little over a month. I am working on an exercise where I ask the user to enter a time in a 24-hour clock format and check if it's valid.

That's not important though. My problem is I'm confused about an error. The below code creates an unhandled exception, and says my input string was not in a correct format. It specifies line 22. (The hour variable.)

Now, I've already fixed it, by moving all the variables except userInput inside the try block. But I'm confused why that fixed it. I'm very new, and have tried googling, but honestly don't really know how to even phrase my question.

The complete (pre-fixed) code is below. I appreciate everyone's patience.

{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter a time value in the 24-hour time format. (ex. 19:00)");
            var userInput = Console.ReadLine();
            var userComponents = userInput.Split(':');
            var hour = Convert.ToInt32(userComponents[0]);
            var minute = Convert.ToInt32(userComponents[1]);    

            if (String.IsNullOrWhiteSpace(userInput))
            {
                Console.WriteLine("Invalid Time");
                return;
            }

            try
            {                      
                if (hour <= 23 && hour >= 00 && minute >= 0 && minute <= 59)
                    Console.WriteLine("Ok");
                else
                    Console.WriteLine("Invalid Time");
            }

            catch(Exception)
            {
                Console.WriteLine("Invalid Time");
            }
       }
    }
}

Someone requested I post the fixed code:

{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter a time value in the 24-hour time format. (ex. 19:00)");
            var userInput = Console.ReadLine();  

            if (String.IsNullOrWhiteSpace(userInput))
            {
                Console.WriteLine("Invalid Time");
                return;
            }

            try
            {
                var userComponents = userInput.Split(':');
                var hour = Convert.ToInt32(userComponents[0]);
                var minute = Convert.ToInt32(userComponents[1]);

                if (hour <= 23 && hour >= 00 && minute >= 0 && minute <= 59)
                    Console.WriteLine("Ok");
                else
                    Console.WriteLine("Invalid Time");
            }

            catch(Exception)
            {
                Console.WriteLine("Invalid Time");
            }
       }
    }
}

Someone also requested the debugger info:

System.IndexOutOfRangeException HResult=0x80131508 Message=Index was outside the bounds of the array. Source=Section 6 24 Hour Time
StackTrace: at Section_6_24_Hour_Time.Program.Main(String[] args) in D:\Repos\Mosh C# Udemy\Exercises\C# Fundamental Exercises\Section 6 24 Hour Time\Section 6 24 Hour Time\Program.cs:line 23

c#
asked on Stack Overflow Nov 4, 2018 by Caleb Twombly • edited Nov 4, 2018 by Caleb Twombly

4 Answers

3

As said in the comments, you're running str.split() and then just accessing the output of it with index 0 and index 1. Upon requesting index 0 or 1 whilst it's not there you'll get an Index out of range exception telling you Item on index 0 or 1 is not there.

Then there's the issue with Convert.ToInt32 as you don't catch an overflowexception or formatexception.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Please enter a time value in the 24-hour time format. (ex. 19:00)");
        var userInput = Console.ReadLine();
        if(string.IsNullOrEmpty(userInput)) {
            Console.WriteLine("No input");
            return;
        }

        if(!userInput.Contains(':')) {
            Console.WriteLine("Input does not have `:` in it. Invalid Time.");
            return;
        }

        var userComponents = userInput.Split(':');
        if(userComponents.Length != 2) { 
            Console.WriteLine("Invalid Time");
            return;
        }
        if(string.IsNullOrEmpty(userComponents[0]) || string.IsNullOrEmpty(userComponents[1]) {
            Console.WriteLine("No hours or minutes given. Invalid Time");
            return;
        }
        try {
            var hour = Convert.ToInt32(userComponents[0]);
            var minute = Convert.ToInt32(userComponents[1]);    
        } catch(OverFlowException e) {
            // Do something with this.
            return;
        } catch (FormatException e) {
            // Do something with this.
            return;
        }

        if (hour <= 23 && hour >= 00 && minute >= 0 && minute <= 59)
            Console.WriteLine("Ok");
        else
            Console.WriteLine("Invalid Time");

   }
}

Edit

As mentioned by @ckuri and What's the main difference between int.Parse() and Convert.ToInt32 one should prefer int.TryParse() over Convert.ToInt32 since we're dealing with user input here.

  • If you've got a string, and you expect it to always be an integer (say, if some web service is handing you an integer in string format), you'd use Int32.Parse().

  • If you're collecting input from a user, you'd generally use Int32.TryParse(), since it allows you more fine-grained control over the situation when the user enters invalid input.

  • Convert.ToInt32() takes an object as its argument. (See Chris S's answer for how it works)

Convert.ToInt32() also does not throw ArgumentNullException when its argument is null the way Int32.Parse() does. That also means that Convert.ToInt32() is probably a wee bit slower than Int32.Parse(), though in practice, unless you're doing a very large number of iterations in a loop, you'll never notice it.

answered on Stack Overflow Nov 4, 2018 by Baklap4 • edited Nov 8, 2018 by Baklap4
2

Before you access the elements of the array, check if it has the desired length:

if (userComponents.Length < 2)
{
    Console.WriteLine("Invalid Time");
    return;
}

var hour = Convert.ToInt32(userComponents[0]);
var minute = Convert.ToInt32(userComponents[1]);

Note that the input string may not contain the colon, so Split will return an array with only one element. In such case userComponents[1] does not exist, hence the exception.

answered on Stack Overflow Nov 4, 2018 by BartoszKP
0

This error indicates that you are trying to convert a string value to int (in this case) that is not castable. So you should make sure that the value you input after splitting is castable to int, also it is nice to Trim() them before casting:

 var hour = Convert.ToInt32(userComponents[0].Trim());
 var minute = Convert.ToInt32(userComponents[1].Trim()); 
-1

before you try to split userInput you should first check for IsNullOrWhiteSpace


User contributions licensed under CC BY-SA 3.0