3

I have trouble implementing the Y/N or y/n in the loop. I've designed it in a way that a user can use both the capital and small letters of the Y and N for their answer in a loop. by the way here's my code but can't seem to make it work:

do
        {
            Console.WriteLine("\nSelect additional topping/s\n");

            Console.WriteLine("1 - Extra meat: 200");
            Console.WriteLine("2 - Extra cheese: 100");
            Console.WriteLine("3 - Extra veggies: 80\n");

            int selectedTopping = Convert.ToInt32(Console.ReadLine());

            switch (selectedTopping)
            {
                case 1:
                    pizza = new MeatToppings(pizza);
                    break;

                case 2:
                    pizza = new CheeseToppings(pizza);
                    break;

                case 3:
                    pizza = new VeggieToppings(pizza);
                    break;

                default:
                    break;
            }

            Console.WriteLine("\nAdd more toppings? Y/N");
            

        }

        while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));
peterh
  • 11,875
  • 18
  • 85
  • 108
Dwayne Radar
  • 195
  • 1
  • 4
  • 10
  • 2
    Shouldn't your `Pizza` class have an `addToppings()` method or a publicly accessible list of toppings? Maybe I've not had enough coffee today but your code doesn't seem to make sense to me. – dreamlax Jan 15 '13 at 06:56
  • 2
    Remember that each time you call `Console.ReadLine()` the program waits for the user to write something and press enter. You have it twice, so in order to continue the user must first type Y and press enter, then type y and press enter. Tilak's answer provides an easy way to do it (you can also cast to lower of course). – MasterMastic Jan 15 '13 at 07:00

6 Answers6

6
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));

This is going to read 2 different lines since you're calling ReadLine() twice. You need to call it once and save the value.

Austin Henley
  • 4,625
  • 13
  • 45
  • 80
  • This is indeed a critical issue with the O.P.'s code, but along those lines, Tilak's answer above is a solid workaround to it. That said, saving user input to a variable is almost always the preferred way to go. – Devin Jan 15 '13 at 06:58
  • 1
    @Devin Indeed, Tilak's way works great. My personal style is to avoid that kind of thing though, so keeping the input in a variable is more readable to me and makes the code almost self-documenting. – Austin Henley Jan 15 '13 at 07:00
  • Agreed, good code should be self-documenting (or at least I subscribe to that philosophy). – Devin Jan 15 '13 at 07:01
6

You can use ToUpper

while ((Console.ReadLine().ToUpper() == "Y") );
Tilak
  • 30,108
  • 19
  • 83
  • 131
  • 5
    String Comparison using ToUpper/ToLower should be discouraged. [The Turkish İ Problem and Why You Should Care](http://haacked.com/archive/2012/07/05/turkish-i-problem-and-why-you-should-care.aspx) – Habib Jan 15 '13 at 07:06
  • 2
    Yes in general, but it is not applied to this question. 'Y' has no issues. That issue comes with character `i`. Also One of the tool (FxCop or StyleCop) complains on using `ToLowerInvariant` in favor of 'ToUpperInvariant' – Tilak Jan 15 '13 at 07:09
6

Try to use String.Equals and StringComparison:

String.Equals(Console.ReadLine(), "y", StringComparison.CurrentCultureIgnoreCase);

from MSDN:

CurrentCultureIgnoreCase: Compare strings using culture-sensitive sort rules, the current culture, and ignoring the case of the strings being compared.

OrdinalIgnoreCase: Compare strings using ordinal sort rules and ignoring the case of the strings being compared.

Ria
  • 10,237
  • 3
  • 33
  • 60
5

To check Y or y ignoring case, you should use string.Equals(string,StringComparison) overload.

while (Console.ReadLine().Equals("Y", StringComparison.InvariantCultureIgnoreCase));

Please see the The Turkish İ Problem and Why You Should Care before using ToUpper or ToLower for string comparison with ignore case.

Your current code is reading the lines from console twice, that is why your code is holding up for the 2nd value.

Habib
  • 219,104
  • 29
  • 407
  • 436
  • This is overkill for checking a single character that is not even affected by Turkish casing. It's important to be aware of things like Turkish casing but it's just as important to know when its relevant. And here it isn't. – dreamlax Jan 16 '13 at 22:53
  • @dreamlax, how it is an overkill ? using ToLower/ToUpper will create a new string and that I believe is an overkill. Yes Turkish casing is not an issue here, but for string comparison with ignore case, `string.Equals` is a much better approach – Habib Jan 17 '13 at 04:26
  • 1
    It's overkill because it's solving a non-existent problem, you've overengineered the requirements. And if creating a new one-character string is the bottleneck of your application's performance then I guess you have a point. – dreamlax Jan 17 '13 at 04:33
  • 2
    @dreamlax, I know the performance bottleneck is negligible. Its about the best practice. See [Best Practices for Using Strings in the .NET Framework](http://msdn.microsoft.com/en-us/library/dd465121.aspx) – Habib Jan 17 '13 at 04:39
1

As Austin just pointed out, you are using ReadLine twice in the while loop statement.

One thing worth mentioning is try to follow the rule of modularity, it will help speed up implementing and debugging our code.

It's been a while since I did any C# programming so sudo-coding this in Java style.

Since it's a command line programming you are probably have to validate user input more than once. One thing I would do is make a utility class to contains common user input tasks.

public class TerminalUtil {
    private TerminalUtil() {}

    public static boolean isYes(String msg){ return (msg.ToUpper() == "Y" || msg.ToUpper() == "YES"); }
    public static boolean isNo(String msg){ return (msg.ToUpper() == "N" || msg.ToUpper() == "NO"); }
   // You also might want basic conditionals to check if string is numeric or contains letters.

    // I like using recursion for command line utilities so having a method that can re-print messages is handy
    public static void display(String[] messages){
        for(String msg : messages){
            Console.WriteLine(msg);
        }
    }

    public static boolean enterYesOrNo(String[] messages, String[] errorMessages){
        display(messages)
        String input = Console.ReadLine();
        if( isYes(input) ){
            return true;
        } else if( isNo(input) ){ 
            return false; 
        } else {
             display(errorMessages); // Maybe something like, you didn't enter a yes or no value.
             enterYesOrNo(messages, errorMessages); // Recursive loop to try again.
        }

    }
}

Here is what the code to order a pizza might look like

public class OrderPizza{
    public static int selectToppings(){
        String[] message = new String[4];
        message[0] = ("\nSelect additional topping/s\n");
        message[1] = ("1 - Extra meat: 200");
        message[2] = ("2 - Extra cheese: 100");
        message[3] = ("3 - Extra veggies: 80\n");

       int option =  TerminalUtils.entryNumeric(message, {"You entered an non-numeric character, try again"} );
       if( option > 0 && option <= 3 ){
           return option;
       } else {
          Console.WriteLine("Number must be between 1 - 3, try again.");
          return selectToppings();
       }
    }

    public static Pizza order(){
        Pizza pizza = new Pizza();

        while(true){
            int toppingCode = selectTopping();
            pizza.addTopping(toppingCode);
            if(!TerminalUtil.enterYesOrNo({"\nAdd more toppings? Y/N"}, {"Please enter a 'Y'es or 'N'o"}) ){
                break;
            }
        }
    }
}

The main benefit of this is that the business logic of the while loop has been reduced and you can reuse the code in TerminalUtils. Also this is by no mean a elegant solution, I'm lazy and it's 3am IRL, but it's should be enough to the ball rolling.

One thing you should probably reconsider doing is using integer codes to represent toppings. Using an enum might make things easier to implement.

I also notice that you add three different types of pizza's, which I'm assuming three separate objects.

Since you are looping to add toppings to a pizza, make an abstract class of pizza. This way you could extend it generic pre-built pizzas such as pepperoni or cheese and use the abstract pizza class if you want the customer to customize their order.

Dan
  • 1,179
  • 2
  • 10
  • 18
0

I didn't found better way than:

while ( str!="N" )
{
    str = Console.ReadLine();
    str = str.ToUpper();
    if (str == "Y");
       break;
};
Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101