Validate user input with multiple criteria c# - c#

I need to validate input based on whether or not it's a number and whether or not it exceeds inventory levels.
So far I can check for inventory level, but I only know how to use tryparse to check if its a number, and I don't want to output anything. Here's what I have so far. It gives an error because I didn't give it a variable.
if (ckbSingle.IsChecked.Value)
{
if (int.TryParse(txtSingQuan.Text, out Convert.ToInt32(txtSingQuan.Text)))
if ((singleespresso.DunkinInventory - Convert.ToInt32(txtSingQuan.Text)) <= 0)
{
MessageBox.Show("Espresso low in stock.");
}
else
{
ProductList.Add("Single Espresso");
}
}
I want it to allow me to continue with the code if the input is appropriate and show a message box if it's not.

It gives an error because I didn't give it a variable
Then give it one:
if (ckbSingle.IsChecked.Value)
{
if (int.TryParse(txtSingQuan.Text, out int qty) && qty >= singleespresso.DunkinInventory)
{
// Input is a valid number and is greater than or equals to stock
ProductList.Add("Single Espresso");
// qty variable is accessible in that scope if need be
}
else
{
// Input is either not a number or lower than stock
MessageBox.Show("Espresso low in stock.");
}
}

Related

C# Creating a list that takes user input and after prints the number from the list within a certain value range.(please explain how and why it works)

using System;
using System.Collections.Generic;
namespace exercise_69
{
class Program
{
public static void Main(string[] args)
{
List<int> numbers = new List<int>();
//creating a list called numbers
while (true)
{
int input = Convert.ToInt32(Console.ReadLine());
if (input == -1)
{
break;
}
numbers.Add(input);
}
//fills a list called numbers until user enters " -1 "
Console.WriteLine("from where");
int lownum = Convert.ToInt32(Console.ReadLine());
//lowest number to get printed
Console.WriteLine("where to");
int highnum = Convert.ToInt32(Console.ReadLine());
//highest number to get printed
foreach(int number in numbers)
{
if(lownum < number || highnum > number)
{
Console.WriteLine(numbers);
} //trying to filter the numbers and print them
}
}
}
}
Blockquote
the issue i am having is when i run the program the console just tells me this
"System.Collections.Generic.List`1[System.Int32]"
so my question is how do i properly filter or remove numbers from a list within a certain value ( not index )
the console just tells me this "System.Collections.Generic.List`1[System.Int32]"
That's because you did this:
Console.WriteLine(numbers);
numbers is a List<int>, it's a whole collection of numbers not just a single number. Console.WriteLine has many varaitions ("overloads") that know how to do all different kinds of things. It has a large quantity of specific variations for numbers, strings, etc and there is one variation that's like a "catch-all" - it accepts an object which means it can accept pretty much anything in the C# universe. The only thing it does with it, if you do manage to end up using this variation (overload), is call ToString() on whatever you passed in, and then print the string it gets back.
Because you passed a List<int> in, and Console.WriteLine doesn't have any variation that does anything cool with a List specifically, it means your passed-in List gets treated by the catch-all version of WriteLine; "call ToString on what was passed in and print the result". Because List doesn't have a very specific or interesting ToString() of its own, it just inherits a version of ToString() from object, the most simple root of all things in C#. Object's ToString() doesn't do very much - it just returns the type of the object which, in this case, is a "System.Collections.Generic.List`1[System.Int32]".. and that's why you see what you see in the console
Now that you know why your code is printing the type of the List, because you're passing in a List, can you see how to change it so you're passing in something else (like, e.g. an actual number you want to print) ?
Console.WriteLine(numbers);
^^^^^^^
this needs to be something else - can you work out what?

Implementing a while loop to check for multiple exceptions in input validity

Sorry if this is a simple question; this is my first language and I'm trying my best to seek out and follow examples and explanations on this site and otherwise.
I've been trying to expand on a Microsoft C# tutorial program that creates "bank accounts." I'm trying to work on catching and handling exceptions, specifically by prompting the user to try again for a valid input.
I've come across this thread and many similar threads about running a loop while the input is invalid, and this example specifically using try/catch, which if I'm understanding correctly, is what I want to use here because I have a few lines of code that could throw multiple exceptions (it could be non-numerical or it could be negative). Following those and other examples, I can't figure out how to assign the initial balance input to a value that I can reference outside the loop (but still only within the CreateAccount method) once the input is valid.
I'm not sure what I have currently is working otherwise, but currently this code produces an error because initBalInput is left unassigned after the while loop, even though it's declared outside the loop and assigned in the try block.
public static void CreateAccount()
{
// Prompt for BankAccount constructor parameter {name} which is passed to BankAccount.Owner in constructor
Console.WriteLine("Name on new account: ");
string nameInput = Console.ReadLine();
decimal initBalInput;
bool valid = false;
while (valid == false)
{
try
{
Console.WriteLine("How much to deposit for initial balance: ");
initBalInput = Convert.ToDecimal(Console.ReadLine());
}
catch (ArgumentOutOfRangeException)
{
Console.WriteLine("Initial balance must be positive!");
valid = false;
continue;
}
catch (FormatException)
{
Console.WriteLine("Initial balance must be a number!");
valid = false;
continue;
}
valid = true;
}
// Create new instance "account" of type BankAccount and set its parameters
BankAccount account = new BankAccount(nameInput, initBalInput);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
}
Instead of catching the exceptions, write the code that handles the invalid input.
public static void CreateAccount()
{
// Prompt for BankAccount constructor parameter {name} which is passed to BankAccount.Owner in constructor
Console.WriteLine("Name on new account: ");
string nameInput = Console.ReadLine();
string initBalInput = Console.ReadLine();
// try parse will check for invalid decimal values and also, positive values can be checked
if(decimal.TryParse(initBalInput, out decimal initBal) && initBal > 0) {
// Create new instance "account" of type BankAccount and set its parameters
BankAccount account = new BankAccount(nameInput, initBal);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
} else {
Console.WriteLine("Invalid initial balance");
}
}
but currently this code produces an error because initBalInput is left unassigned after the while loop, even though it's declared outside the loop and assigned in the try block
The problem is that the compiler doesn't know if execution will ever reach the try block:
while (valid == false)
is evaluated at runtime. You and me both know that execution will enter at least once the while loop because valid is initially false but the compiler doesn't go into that type of analysis where variables are involved and therefore assumes execution might never enter the while loop and an unitialized initBalInput can be read.
That said, you should not get into the habit of using exepctions as control flow mechanisms. Exceptions should be exceptions, don't base the logic of your programs around exceptions. In your case, you should look into the method decimal.TryParse.
Also, always break up your problem into smaller problems. At the beginning, start small, make one liner methods that are obviously correct. It's very hard to write a bug in methods that are one or two lines long.
So what do you need?
A method that prompts the user for an input.
A method that validates the input
Something that asks the user to try again if the input is wrong.
Ok, numer one:
static string RequestUserInput(string message)
{
Console.Write(message);
return Console.ReadLine();
}
Number two: We already have it with decimal.TryParse(string, out decimal d). This method will return true if the input string can be parsed into a valid decimal number which will be assigned to d and false otherwise.
Number three:
public static decimal GetDecimalInput(string message)
{
decimal d;
while (true)
{
if (!decimal.TryParse(RequestUserInput(message), out d))
//tryparse failed, input is not a valid decimal number
Console.WriteLine("Initial balance must be a number!");
else if (d < 0) //try parse succeeded, we know input is a valid
// decimal number d but it might be negative.
Console.WriteLine("Initial balance must be positive!");
else
//we know inout is a valid non negative decimal number.
//break out of the loop, we don't need to ask again.
break;
}
return d;
}
And now, you put it all together:
var accountBalance = GetDecimalInput("How much to deposit for initial balance: ");
First, I have two articles on Exception handling that I consider required reading:
This one helps to classify the 4 common exception types - and if you should even consider catching them.
While this one goes into more details for good practices.
You should not be using convert, but parse. Or even better TryParse(). The exceptions on the string -> number conversion are the examples for vexing exceptions.
If there is no TryParse, I did once wrote a custom implementation of Int.TryParse() for someone still on Framework 1.1:
//Parse throws ArgumentNull, Format and Overflow Exceptions.
//And they only have Exception as base class in common, but identical handling code (output = 0 and return false).
bool TryParse(string input, out int output){
try{
output = int.Parse(input);
}
catch (Exception ex){
if(ex is ArgumentNullException ||
ex is FormatException ||
ex is OverflowException){
//these are the exceptions I am looking for. I will do my thing.
output = 0;
return false;
}
else{
//Not the exceptions I expect. Best to just let them go on their way.
throw;
}
}
//I am pretty sure the Exception replaces the return value in exception case.
//So this one will only be returned without any Exceptions, expected or unexpected
return true;
}
But that code looks like you want to have detailed information why it failed. At wich point you may have to write a detailed list of catch blocks.

!int.TryParse What am i doing wrong?

I am making a pretty easy assignment.
I have a textbox and a button, if the user fills in a number it'll check if it's the correct number. Now I want to make sure that the user input is a number, if it's not then I want a message box to appear that ask to fill in a number. I made the following code but it's giving me an error when i fill in a letter in the textbox. Why?
private void guessBtn_Click(object sender, EventArgs e)
{
int number
number = Convert.ToInt32(numberTb.Text);
if (!int.TryParse(numberTb.Text, out number)){
MessageBox.Show("This isn't a number");
} else if (number == 3) {
MessageBox.Show("Correct!");
} else if (number < 3) {
MessageBox.Show("Incorrect, number must be higher");
} else {
MessageBox.Show("Incorrect, number must be lower");
}
}
TryParse doesn't just return whether the string can be converted to an integer. It actually does the conversion, and puts the result in the out parameter.
Therefore, you don't need a Convert.ToInt32 call before calling TryParse.
You got an exception because Convert.ToInt32 will throw an exception if the string is invalid. Basically, your program terminated because of Convert.ToInt32 before it even reaches TryParse.
So, remove the Convert.ToInt32 line.

I give input 1 to 9.. if the same input occurred 5 times with in 30 sec I want to print that

public class call
{
DateTime time = DateTime.Now;
public void check()
{
int count=0;
if(time < time.AddSeconds(30))
{
count ++;
if(count == 5)
{
Console.WriteLine(count);
}
}
public class Program
{
public static void Main(string[] args)
{
int input;
string sinput;
call one = new call();
call two = new call();
sinput = Console.ReadLine();
input = int.Parse(sinput);
do{
switch(input)
case 1: one.check();
break;
case 2: two.check();
break;
default: Console.WriteLine(":::");
break;
}while(input > 9)
}
}
}
I am new to programming...
I tried to print the number If it occurred 5 time within 30 sec...
I give input 1 to 9.. if the same input occurred 5 times with in 30 sec I want to print that..
You have a few bugs:
You'll probably want to replace:
if(time < time.AddSeconds(30))
With something the compares to the current time such as:
if(DateTime.Now < time.AddSeconds(30))
You are also incrementing count twice in your check method, not sure if that was intentional.
Inside of your do loop your switch body needs to be inside of {} and you probably should be reading a new input each time or doing something else to change the input or your loop will run forever.
You should also always validate user input. In this case if someone enters something other than a number your application will crash form this code:
sinput = Console.ReadLine();
input = int.Parse(sinput);
Instead lookup the int.TryParse method.
You create something like a class that logs the data for a certain input value (that is, stores the dates at which they are entered) and a class that binds those. Like, in pseudo-code:
class SingleInputLogger {
List<Date> dates
void addDate(Date date){
push date in dates
}
unsigned int currentSize(){
remove all entries from dates which are too old
return size of dates
}
}
class InputLogger {
Array<SingleInputLogger> singleInputLoggers of size 10 (or 9 if only 1..9, but then mind the offset)
//adds an input and also returns true if the input has a count of more than five
void addInput(int input){
singleInputLoggers[input].addDate(currentTime())
}
bool checkInput(int input){
if(singleInputLoggers[input].currentSize() >= 5){
return true
}
return false
}
Then the main routine becomes
InputLogger logger
while(get input){
logger.addInput(input)
if(logger.checkInput(input)){
display message "input " + input + " was entered more than five times in 30s"
}
}
(List was used to indicate a linked list in order to be able to efficiently remove front entries, Array was used to indicate a structure of static size for fast access)
Remember to let classes like this do the job for you. Try to use as less functions as possible and rather go with methods.
If someone has better names for those classes (I admit that my names are not that great), feel free to edit my answer.

Converting Strings to Ints

Alright, nub question. I know. Basic response might be
Convert.ToInt32(string);
But naturally, C# does every natural process to make sure just that doesn't happen.
Here's my code:
while (true)
{
while (true)
{
//ask for time
Console.WriteLine("What is the hour?");
Console.WriteLine();
string s = Console.ReadLine();
//convert input to int
YourTime.nHour = Convert.ToInt32(s);
//check to see if it's legal
if ((YourTime.nHour <= 12) || (YourTime.nHour > 0))
{
break;
}
//etc etc code
}
}
I want to make sure the input is an actual hour. When I run this code, it always labels the if() statement as "true" and breaks, even if I inputted something like -13 or 99.
I'm sure there's a simple replacement for "Convert.ToInt32(s);", but to be honest it seems like I've tried everything. I decided it would be best to follow step-by-step instructions from people who are aware of the code at hand.
[EDIT] - Wrong operator, not the conversion. Thanks to everyone who helped!
You need to use AND not OR. So, change it to
if ((YourTime.nHour <= 12) && (YourTime.nHour > 0))
It's your if statement that's invalid, not the Convert.ToInt32
if ((YourTime.nHour <= 12) || (YourTime.nHour > 0)) will always be true. I think you meant to do if ((YourTime.nHour <= 12) && (YourTime.nHour > 0))
Do you mean no matter what integer you type in it always breaks?
If so its because no matter what integer you type in it will always pass one of those conditions.
i.e If I entered 10000000, it would still be greater than 0
and if I entered -10000000 it would still be less than 12
You just mixing two things that should not be mixed.
Converter from string to int should not have any business logic incorporated, that is model responsibility to know that this field is actually hours and not payment amount due
So to separate it you can use many things, for example data annotations, take a look at following code
public class MyTime
{
[Require]
[Range(0, 12, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Hours { get; set; }
[Require]
[Range(0, 59, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Minutes { get; set; }
}
this way you have model defined which can be validated against rules it knows about and you can get error message that has sense
PS this link can show you how to create custom validator if you are using data annotations outside asp.net mvc

Categories

Resources