Search code examples
c#goto

Is this a good use of goto statement?


I am writing a simple C# console application in which I am solving the problem by using a GoTo statment to return to the label if the input for UserId is not valid.

But I am not sure if I am using the statement correctly. I would like to work around if there is a better way to solve the problem, even without using GoTo statement?

public void CreateAccount()
{
    Console.WriteLine("----- Create New Account -----\n" +
        "Enter following account information:\n");

    getUserID:
    {
        Console.WriteLine("Enter a UserID (Alphanumeric; no special characters): ");
        string userid = Console.ReadLine();
        if (!ValidUserID(userid))
        {
            Console.WriteLine("Userid can only contain A-Z, a-z & 0-9. Try again");
            goto getUserID;
        }
        if (data.IsUserInFile(userid))
        {
            Console.WriteLine("Userid already exists. Try again");
            goto getUserID;
        }
    }
}

I will be using the same approach for other fields such as Pin, AccountType, Balance, AccountStatus etc. so I want to ensure that I am doing this in the right manner before I expand its use.


Solution

  • A simple approach would be to use an if/else if/else construct:

    public void CreateAccount()
    {
        Console.WriteLine("----- Create New Account -----\n" +
            "Enter following account information:\n");
    
        string userid = null;
        while (true)
        {
            Console.WriteLine("Enter a UserID (Alphanumeric; no special characters): ");
            userid = Console.ReadLine();
            if (!ValidUserID(userid))
            {
                Console.WriteLine("Userid can only contain A-Z, a-z & 0-9. Try again");
            }
            // if the condition above isn't matched, we'll check this condition
            else if (data.IsUserInFile(userid))
            {
                Console.WriteLine("Userid already exists. Try again");
            }
            // if that isn't matched either, then we have an acceptable userid and can exit the loop
            else
            {
                break;
            }
        }
    }
    

    Note that I've moved the userid declaration out of the loop, since you presumably need to use it after the loop.

    Alternatively, you could potentially break up your code a little more. The whole method for reading the userId could be moved out into its own method:

    public string ReadUserId()
    {
        while(true)
        {
            // Prompt and read answer
            Console.WriteLine("Enter a UserID (Alphanumeric; no special characters): ");
            string userId = Console.ReadLine();
            
            // If the id is valid, return it and leave the method (ending the loop)
            if (ValidUserId(userId))
            {
                return userId;
            }
            
            // If we got here, then the id is invalid and we should inform the user to try again
            Console.WriteLine("Userid can only contain A-Z, a-z & 0-9. Try again");
        }
    }
    

    Now in the main method we can reference this method when we need to obtain a userId. The loop for checking if the user already exists can now be implemented separately to reading the user input, so there are no longer concerns about two different conditions:

    public void CreateAccount()
    {
        Console.WriteLine("----- Create New Account -----\n" +
            "Enter following account information:\n");
    
        string userId = null;
        bool isNewUser = false;
        while (!isNewUser)
        {       
            // Use our other method to read the user id
            userId = ReadUserId();
        
            if (data.IsUserInFile(userId))
            {
                Console.WriteLine("Userid already exists. Try again");
                continue;
            }
            
            isNewUser = true;
        }
    }