Console.ReadLine unexpected behaviour in else-if statement - c#

I'm having some trouble with my console application.
I want to check the user input and execute something depending on what the user wrote. My code looks something like this:
if(Console.ReadLine() == "ADD")
{
//Add
}
else if (Console.ReadLine() == "LIST")
{
//DisplayList
}
else if (Console.ReadLine() == "SORT")
{
//Sort
}
else
{
//DisplayErrorMsg
}
Now when i type LIST in the console, i get a line-break, and I have to type LIST again to get expected behaviour, and all following else-if statements just add another line-break. (example below)
I've looked everywhere I can but I can't see what I've done wrong...
Please help!
SORT
SORT
SORT
//Sorting...

You are invoking ReadLine multiple times and therefore you read multiple times from the stdin. Try the following:
var line = Console.ReadLine();
if (line == "ADD")
{
//Add
}
else if (line == "LIST")
{
//DisplayList
}
else if (line == "SORT")
{
//Sort
}
else
{
//DisplayErrorMsg
}

Try to get line in a string, and so test the string.
string line = Console.ReadLine();
if (line == "ADD")
{
//Add
}
else if (line == "LIST")
{
//DisplayList
}
else if (line == "SORT")
{
//Sort
}
else
{
//DisplayErrorMsg
}

Every time you call Console.ReadLine() it will wait for user input.
Assign the value returned from running Console.ReadLine() to a variable.
Then do your if, else checks on that variable.
var userInput = Console.ReadLine();
if(userInput == "ADD")
{
//Add
}
else if (userInput == "LIST")
{
//DisplayList
}
else if (userInput == "SORT")
{
//Sort
}
else
{
//DisplayErrorMsg
}

string readfromConsole = Console.ReadLine()
if(readfromConsole == "ADD")
{
//Add
}
else if (readfromConsole == "LIST")
{
//DisplayList
}
else if (readfromConsole == "SORT")
{
//Sort
}
else
{
//DisplayErrorMsg
}
The problem you are having is that Console.readLine does exactly what it says it reads a new line. So what this change does is it saves the first read and compares against that instead of reading a new line each time. I hoped this helped

Related

Only allowing yes or no as an answer

I am a complete newbie and i am stuck on a small problem
I want the user to only be able to have yes or no as an answer.
This is what I came up with
static public bool askBool(string question)
{
try
{
Console.Write(question);
return Console.ReadLine() == "y";
}
catch (Exception)
{
throw new FormatException("Only y or n Allowed");
}
}
The problem is entering any other letter then 'y' will result in false, how can I best solve this ?
Thank you in advance.
EDIT (from comment question)
try
{
Console.Write(question);
return int.Parse(Console.ReadLine());
}
catch (Exception)
{
throw new FormatException("Please Enter a Number");
}
I doubt if you want an exception to be thrown - there's nothing exceptional if the user puts OK instead of yes; I suggest to keep asking until "yes" or "no" are read:
public static AskBool(string question) {
while (true) {
// If we have a question to ask (the question is not empty one)...
if (!string.IsNotNullOrWhiteSpace(question))
Console.WriteLine(question); // ... ask it
// Trim: let be nice and trim out leading and trailing white spaces
string input = Console.ReadLine().Trim();
// Let's be nice and accept "yes", "YES", "Y" etc.
if (string.Equals(input, "y", StringComparison.OrdinalIgnoreCase) ||
string.Equals(input, "yes", StringComparison.OrdinalIgnoreCase))
return true;
else if (string.Equals(input, "n", StringComparison.OrdinalIgnoreCase) ||
string.Equals(input, "no", StringComparison.OrdinalIgnoreCase))
return false;
// In case of wrong user input, let's give a hint to the user
Console.WriteLine("Please, answer yes or no (y/n)");
}
}
Here the method will only return true or false if user has entered true or false.If user enters any word the loop will just continue to ask him for input until he enters y or n
you can give it a try by doing following changes
static public bool askBool(string question)
{
bool boolToReturn = false;
Console.Write(question);
while (true)
{
string ans = Console.ReadLine();
if (ans != null && ans == "y")
{
boolToReturn = true;
break;
}
else if ( ans != null && ans == "n")
{
boolToReturn = false;
break;
}
else
{
Console.Write("Only y or n Allowed");
}
}
return boolToReturn;
}`
Answer to second question:-
`
public static int askInt(string question)
{
Int intToReturn = false;
Console.Write(question);
while (true)
{
string ans = Console.ReadLine();
if (int.TryParse(and,out intToreturn))
break;
else
Console.Write("Only number Allowed");
}
return intToReturn;
}`
A bit more simplified version of Dmitry's answer with switch (what I normally do for this kind of scenarios):
static public bool askBool(string question)
{
while(true)
{
Console.Clear();
Console.Write(question);
var input = Console.ReadLine().Trim().ToLowerInvariant();
switch (input)
{
case "y":
case "yes": return true;
case "n":
case "no": return false;
}
}
}
Also I'd consider changing .ReadLine() to .ReadKey() because what we really need here is just 'y' or 'n'... One key is enough.
We use Exceptions mostly for scenarios when unexpected value will lead to some error. We don't throw an exception when we expect user to enter rubbish values and handle them.
You want to throw the exception, not catch it. Example:
static public bool askBool(string question)
{
Console.Write(question);
var input = Console.ReadLine();
if (input == "y")
{
return true;
}
else if(input == "n")
{
return false;
}
else//It's not y or n: throw the exception.
{
throw new FormatException("Only y or n Allowed");
}
}
Of course, you must then capture the 'FormatException' where you call this method.
Something like this?
if (Console.ReadLine() == "y")
{
return true;
}
else if (Console.ReadLine() == "n")
{
return false;
}
else {
throw new Exception("only y and n allowed...");
}
Here another idea:
public static bool ReadUserYesOrNo()
{
bool userSaysYes = true;
Console.Write("Y\b");
bool done = false;
while (!done)
{
ConsoleKeyInfo keyPressed = Console.ReadKey(true); // intercept: true so no characters are printed
switch (keyPressed.Key) {
case ConsoleKey.Y:
Console.Write("Y\b"); // print Y then move cursor back
userSaysYes = true;
break;
case ConsoleKey.N:
Console.Write("N\b"); // print N then move cursor
userSaysYes = false;
break;
case ConsoleKey.Enter:
done = true;
Console.WriteLine();
break;
}
}
return userSaysYes;
}
This will print the default value Y to the console. By pressing Y or N the user can toggle between the two values. The character in the console output will be overwritten. Pressing 'enter' selects the choice and the method returns the result.

Add a second command that calls another method?

I'm remaking a text-based adventure game. During the character creation, I'd like for the user, at any time, to type 'skillset' and list all the traits that a specific race has. I've tried for a couple hours and can't seem to figure it out.
This is my character creation class.
public string userCommand_SeachSkill;
SkillSet searchSkill = new SkillSet();
public void Create_Character()
{
// CHOOSE GENDER //
do
{
validate = 0;
Console.Clear();
Console.Write("Are you male or female? (f/m): ");
Sex = Console.ReadLine().ToUpper();
if (Sex == "M" || Sex == "F")
{
validate = 1;
}
else if (Sex != "M" || Sex != "F")
{
Console.WriteLine("You must enter 'm' or 'f'");
}
} while (validate == 0);
And this is my Skill Set Class. Everything in the if/else statements are methods to print the traits of a race to the console. Let me know if there is anything else I can add to better ask my question. Thank you in advance! :)
ClassAttributes classes = new ClassAttributes();
Character character = new Character();
skillset = Console.ReadLine().ToUpper();
do
{
validate = 0;
if (skillset == "HUMAN")
{
classes.SkillSetHuman();
}
else if (skillset == "ORC")
{
classes.SkillSetOrc();
}
else if (skillset == "ELF")
{
classes.SkillSetElf();
}
else if (skillset == "EXIT")
{
validate = 1;
character.Create_Character();
}
} while (validate == 0);
I think you're looking for something like an event. C# Console Applications only seem to have one kind of event, it fires when ctrl+c or ctrl+break happens. You could handle your skillset input/output logic in the function handler
You can read more here:
https://msdn.microsoft.com/library/system.console.cancelkeypress(v=vs.110).aspx
If you really need the word to be typed, you could capture everything that is typed in a special function, instead of using regular Console.ReadLine(). Something like this:
public static string CustomReadLine()
{
ConsoleKeyInfo cki;
string capturedInput = "";
while (true)
{
cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.Enter)
break;
else if (cki.Key == ConsoleKey.Spacebar)
{
capturedInput += " ";
Console.Write(" ");
}
else if (cki.Key == ConsoleKey.Backspace)
{
capturedInput = capturedInput.Remove(capturedInput.Length - 1);
Console.Clear();
Console.Write(capturedInput);
}
else
{
capturedInput += cki.KeyChar;
Console.Write(cki.KeyChar);
}
if (capturedInput.ToUpper().Contains("SKILLSET"))
{
capturedInput = "";
skillsetTyped();
return "";
}
}
return capturedInput;
}
then inside your Create_Character, do
...
do
{
Console.Write("Are you male or female? (f/m): ");
Sex = CustomReadLine();
} while (String.IsNullOrEmpty(sex));
And finally, handle the skillset logic here
protected static void skillsetTyped()
{
Console.Write("\nWrite your skillset capture/display logic here\n");
}
This is just a draft and has some minor bugs, but I believe it's close to what you really want.

How to Check for valid input c#

i'm trying to make this method like, if you haven't pressed the correct value a message box will show and when you press the messagebox it will return and you have to try to put the rigth values in again and so on. And if the field is null or empty is has to give =0.. If i press ex. e2 it has to pup up with the message box??
have tried this one without the else if.. and the messagebox vil not disappear? please help
public int playerOneDart1Value;
public int calculateDart1()
{
if (player == "t1" || player == "T1" || player == "3")
{
playerOneDart1Value = 3;
}
else if (player == null) or empty??
{
playerOneDart1Value = 0;
}
else
{
MessageBox.Show("not valid input");
return calculateDart1();
}
return playerOneDart1Value;
}
You're calling return calculateDart1(); straight after showing the message box, so the user never has a chance to alter the input, before the check being made again, and showing the message box.
You are calling the function calculateDart1 recursively and so the reason the messagebox won't disappear is that MessageBox.Show("not valid input"); is being called over and over again.
You're calling calculateDart1() right after the MessageBox prompt which results in an endless loop which makes the user unable to provide new input. For your "null or empty" requirement, you can use string.IsNullOrEmpty which returns true if a string is either null or empty.
public int playerOneDart1Value;
public int calculateDart1()
{
if (string.IsNullOrEmpty(player))
{
playerOneDart1Value = 0;
}
else if (player == "t1" || player == "T1" || player == "3")
{
playerOneDart1Value = 3;
}
else
{
MessageBox.Show("not valid input");
//you can use something like a negative value to indicate invalid input
playerOneDart1Value = -1;
}
return playerOneDart1Value;
}

Can this if-else-else logic be rewritten into something neater?

Could I write the following logic in a simpler, more easy-to-read way? The below does what I need, but it is very messy:
if (IsChanged == true)
{
return;
}
// Executed when the close (x) button is pressed,
// as the Status string is not yet set to a real value...
else if (Status == "" && IsChanged == false)
{
CancelClose();
}
// saving logic falls to here...
else if (IsChanged == false && Status == "saving")
{
IsChanged = false;
}
Thanks
if (isChanged) return;
switch (Status) {
case "":
CancelClose();
break;
case "saving":
// IsChanged = false;
break;
}
This is about as neat as it gets. Note that because you return if isChanged is true you can further on always assume that isChanged is false.
This is a bit cleaner:
if (IsChanged)
{
}
else if (Status == "saving")
{
}
else if (Status == "")
{
}
else
{
}
I would recommend you use an enum to represent the status. This will allow your code to be strongly typed.
public enum Status
{
Closing,
Saving,
Changed,
}
Then you can use a nice switch statement to decide what action to take.
switch (_status)
{
case Status.Saving:
break;
case Status.Closing:
break;
case Status.Changed:
break;
default:
break;
}
if(IsChanged)
return;
if(Status == "saving")
{
// save
}
else if(string.IsNullOrEmpty(Status))
{
CancelClose();
}
Since you return if IsChanged==true, you don't need it in the other ifs.
if (IsChanged == true)
return;
switch (Status)
{
case "":
CancelClose();
break;
case "saving":
break;
}
yes:
if (IsChanged) return;
if (String.IsNullOrEmpty(Status)) CancelClose();
cut the first else if to just if. If IsChanged is true the "else" will never be reached.
remove the IsChanged==false from your other ifs because they are always true.
Think about enums instead of strings for your status.
I'd recommend:
if (IsChanged)
{
return;
}
if (CurrentStatus == Status.None)
{
CancelClose();
return;
}
if (CurrentStatus == Status.Saving)
{
// IsChanged = false;
}
if(!IsChanged) {
if (Status == "saving") // saving logic falls to here...
{
// IsChanged = false;
}
else if (Status == "") // Executed when the close (x) button is pressed, as the Status string is not yet set to a real value...
{
CancelClose();
}
} else {
return;
}
It can be simplifed in to
if (IsChanged)
{
return;
}
else if (Status == "") // Executed when the close (x) button is pressed, as the Status string is not yet set to a real value...
{
CancelClose();
}
else if (Status == "saving") // saving logic falls to here...
{
// IsChanged = false;
}
You do not need the == True in the first check, as it already is true or false. you do not need to check for false in the other choices because if it is not true it must be false.
if (IsChanged) return;
if (Status == "saving")
{
//IsChanged = false;
}
else if (Status = "")
{
CancelClose();
}
I'd avoid beginning your variable names with uppercase.
if (IsChanged)
return;
if (String.IsNullOrEmpty(Status)) // better use this unless you would like a
CancelClose(); // nullPointerException
else if (Status.equals("Saving"))
// whatever you want for save
I'm not familiar with c#, but it supports the conditional operator
condition ? first_expression : second_expression;
Since I'm not familiar with c#, I won't try to re-write your code, but in any case, the ternary operator can lead to pleasing concision in some places.

Whats the problem in this function C#

I have written the below function to select a numeric string such as 1,23,000.00
In the WebBrowser I am trapping Double_Click Event and then passing the selected range to the below function.
lets say the initial selection was 000 and my target is to select the whole string as mentioned above.
myRange=doc.selection.createRange()
myRange=SelectCSNumbers(myRange)
I am returning a Range object from the below function. The issue here is
return tmpRange.duplicate();//here it should terminate
count++;
when I am returning the final range this method is getting called again
How I dont know, Can anyone pointout my mistake.
private mshtml.IHTMLTxtRange SelectCSNumbers(mshtml.IHTMLTxtRange myRange)
{
mshtml.IHTMLTxtRange tmpRange = myRange.duplicate();
string[] strInt = tmpRange.text.Split(',');
bool result = false;
result = CheckText(tmpRange, strInt, result);
if (result && count==0)//
{
//Expand the Range with a single Character
tmpRange.expand("character");
if (tmpRange.text.Length > myRange.text.Length)
{
if (tmpRange.text.IndexOf(' ') == -1) //if no space is found that means the selection is not proper
{
//Check for ,/.
if (tmpRange.text.IndexOf(',') == -1)//if NO Comma is found
{
if (tmpRange.text.IndexOf('.') == -1)
{
//EOS
}
else
{
//. is found
SelectCSNumbers(tmpRange.duplicate());
}
}
else
{
SelectCSNumbers(tmpRange.duplicate());
}
}
else if (tmpRange.text.IndexOf(' ') != -1)
{
tmpRange = myRange.duplicate();
tmpRange.moveStart("character", -1);
if (tmpRange.text.IndexOf(' ') == -1) //if no space is found that means the selection is not proper
{
//Check for ,/.
if (tmpRange.text.IndexOf(',') == -1)//if NO Comma is found
{
if (tmpRange.text.IndexOf('.') == -1)
{
//EOS
}
else
{
//. is found
SelectCSNumbers(tmpRange.duplicate());
}
}
else
{
SelectCSNumbers(tmpRange.duplicate());
}
}
}
}
else if (tmpRange.text.Length == myRange.text.Length)
{
tmpRange = myRange.duplicate();
tmpRange.moveStart("character", -1);
if (tmpRange.text.Length == myRange.text.Length)
{
//tmpRange = null;
return tmpRange.duplicate();//here it should terminate
count++;
}
else if (tmpRange.text.IndexOf(' ') == -1) //if no space is found that means the selection is not proper
{
if (tmpRange.text.IndexOf(',') == -1)//if NO Comma is found
{
if (tmpRange.text.IndexOf('.') == -1)
{
//EOS
}
else
{
//. is found
SelectCSNumbers(tmpRange.duplicate());
}
}
else
{
SelectCSNumbers(tmpRange.duplicate());
}
}
}
}
return tmpRange.duplicate();
}
This doesn't help immediately, but addresses a bigger problem
This code needs to be refactored. It will cause problems for you down the line. You have copy-pasted code that will be a pain to take care of. And also, it makes it harder for others to help.
Here is a suggestion for a refactoring (Not Tested)
private mshtml.IHTMLTxtRange SelectCSNumbers(mshtml.IHTMLTxtRange myRange)
{
mshtml.IHTMLTxtRange tmpRange = myRange.duplicate();
string[] strInt = tmpRange.text.Split(',');
bool result = false;
result = CheckText(tmpRange, strInt, result);
if (result && count==0)//
{
//Expand the Range with a single Character
tmpRange.expand("character");
if (tmpRange.text.Length > myRange.text.Length)
{
if (tmpRange.text.IndexOf(' ') == -1) //if no space is found that means the selection is not proper
{
SomeOtherFunction(tmpRange);
}
else if (tmpRange.text.IndexOf(' ') != -1)
{
tmpRange = myRange.duplicate();
tmpRange.moveStart("character", -1);
SomeOtherFunction(tmpRange);
}
}
else if (tmpRange.text.Length == myRange.text.Length)
{
tmpRange = myRange.duplicate();
tmpRange.moveStart("character", -1);
if (tmpRange.text.Length == myRange.text.Length)
{
//tmpRange = null;
return tmpRange.duplicate();//here it should terminate
count++;
}
else if (tmpRange.text.IndexOf(' ') == -1) //if no space is found that means the selection is not proper
{
SomeOtherFunction(tmpRange);
}
}
}
return tmpRange.duplicate();
}
private void SomeOtherFunction(mshtml.IHTMLTxtRange tmpRange)
{
if (tmpRange.text.IndexOf(',') == -1)//if NO Comma is found
{
if (tmpRange.text.IndexOf('.') == -1)
{
//EOS
}
else
{
//. is found
SelectCSNumbers(tmpRange.duplicate());
}
}
else
{
SelectCSNumbers(tmpRange.duplicate());
}
}
Random guess:
if (tmpRange.text.Length == myRange.text.Length)
{
count++;
return tmpRange.duplicate();
}
If you put count++ after the return statement, it will never be executed.

Categories

Resources