Trouble with generic method - c#

so I've been assigned a cinema project to complete for college, which involves me taking input of type Int and DateTime. I decided to create a method to speed up the error handling for every single variable that requires checking.
static T CheckInput <T> (string message, string errorMessage, T lowerBound, T higherBound)
{
T input;
do
{
Console.Write(message);
try
{
input = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
}
catch
{
input = lowerBound;
}
if (input > higherBound || input < lowerBound) Console.Write(errorMessage);
} while (input > higherBound || input < lowerBound);
return input;
}
This should technically allow me to take input of type int and Datetime, which is all I need it to do. However upon running it, the code keeps running until the datetime is valid andthen just continues the while loop without printing the user's ticket.
while (true)
{
// Print List of films
Console.Write("Welcome to Aquinas Multiplex\nWe are currently showing:\n");
for (int i = 0; i < films.Length; i++)
{
Console.Write("{0}. {1} ({2})\n", i + 1, films[i], filmAges[i]);
}
// Error checking for film and age input
filmToSee = CheckInput<int>("Please enter the number of the film you want to see: ", "That is not a valid film\n", 1, films.Length);
age = CheckInput<int>("Please enter your age: "," Not a valid age!\n", 1, 101);
// Age check
if (age < filmAges[filmToSee - 1])
{
Console.Write("ACCES DENIED - TOO YOUNG!\n(Press any key to proceed back to homepage)");
Console.ReadKey();
Console.Clear();
continue;
}
bookDate = CheckInput<DateTime>("Please enter the date you wish to see the film (must be no longer than a week in advance): ", "Not a valid date!\n",DateTime.Now.Date, DateTime.Now.Date.AddDays(7));
Console.Clear();
Console.Write("Your ticket:\n\n--------------------\nAquinas Multiplex\nFilm : {0}\nDate : {1}\n\nEnjoy the film!\n--------------------\n\n(Press any key to go back to the main menu)", films[filmToSee-1], bookDate.Date);
Console.ReadKey();
Console.Clear();
}
What is wrong with the code? I don't see anything in the while loop that would stop the final few lines and I have tried multiple ways to get the generic to output correctly. (Inputting an int to it works as intended, it's just not working for DateTime).

Go back to basics and add Exception handling. Wrap in try catch blocks and write the exception to console. It is important to always apply best practices. Also remember to leverage off the debugger built into your IDE and step through your code to see what it does, and what exceptions are thrown.
You will get a compilation error here:
if (input > higherBound || input < lowerBound) Console.Write(errorMessage);
So, I am not sure how this is running? You cannot compare greatness between T and T they are constrained to type IComparable<T>. Then you can use T.CompareTo(T). Refer to the where (generic type constraint).

Related

Why does the error message not show for the first try, but works fine for the other?

Can someone please tell me why the first try catch is not showing an error message when the user inputs invalid format of data, i.e inputs integar instead of string. If I input numbers instead of letters, the program just accepts it and moves forward.
The other try catch for age is working fine.
public void add_passenger()
{
// Defining variables for name and age to be input
string name;
int age;
//Show message on a clean, new screen
Console.Clear();
Console.WriteLine("==> Welcome aboard <==");
Console.WriteLine(" Please follow instructions to add yourself as a passenger ");
Console.WriteLine("");
// Ask user to input name
while (true)
{
Console.WriteLine(" Your name: ");
//Try and catch in case the user inputs wrong format
try
{
name = Console.ReadLine();
break;
}
catch //This doesn't work
{
Console.WriteLine(" Wrong input format. Please try again and input a rider.");
continue;
}
}
// Ask user to input age
while (true)
{
Console.WriteLine(" Your age: ");
//Try and catch in case the user inputs wrong format
try
{
age = Convert.ToInt32(Console.ReadLine());
break;
}
catch
{
Console.WriteLine(" Wrong input format. Please write an integer.");
continue;
}
}
// Search the array for an empty slot to input the new passenger into
for (int i = 0; i < passengers.Length - 1; i++)
{
if (passengers[i] == null)
{
passengers[i] = new Passagerare(name, age);
break;
}
else
{
continue;
}
}
Console.WriteLine("");
Console.WriteLine(" You have now boarded the bus. Welcome aboard!" );
Console.ReadKey(true);
}
The first try/catch block is working properly as well. It's up to you, the developer to determine what value a string can contain in order for it to be valid or invalid.
In terms of the language, both "john doe" and "123151" are valid strings (the second one is just a string representation of digits). Keep in mind that the code interprets these two very differently:
"123151"
123151
The first is a string with the value "123151".
The second is an integer with the value 123151.
When you read from the console.ReadLine() function into a string variable, you will get a string value of whatever value is input.
What I would suggest, moving forward, is that you add some sort of programming to verify that the value that is input is more like the value your program is expecting. For example, if you're not expecting the string to have any numbers in it, you could check the string for integer values, and throw the exception if any are found. You might even use Regular Expressions to help identify integers or other invalid values.

Where do i put the try-catch in my for-loop?

I'm now done with the basics of my code, and it works like it should. But now i want to add a try-catch exception so that if the user put is anything else than integers, it will throw an exception and say something like: Wrong input try again. Here is where i need it:
for (int i = 0; i < nummer.Length; i++)
{
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
int element = Convert.ToInt32(str);
nummer[i] = element;
}
The loop will loop 10 times and store the inputs in an array. When i try it either makes an exception but contiues the loop or breaks the loop and goes on to the next block of code..
I would favour the use of...
bool parsed = Int.TryParse(str, out myInt);
If (parsed)
{
// do something
}
IMHO, a try/catch block should only really be used when there is a possibility on an unhandled exception (e.g. something volatile such as filesystem interaction) that cannot be "predicted" so as to handle accordingly (e.g. log errors etc.) and then continue without crashing your program.
Always try and handle a "known" with the methods and functions available in the framework to do so.
What you're trying to do doesn't require a try-catch. You can use the TryParse method to check whether the desired input is a properly formed integer, and prompt the user to enter a different input.
for (int i = 0; i < nummer.Length; i++)
{
bool isAnInteger = false;
int element = 0;
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
// evaluates to true if str can be parsed as an int, false otherwise
// and outputs the parsed int to element
isAnInteger = int.TryParse(str, out element);
while (!isAnInteger)
{
Console.Write("Wrong input, try again. ");
str = Console.ReadLine();
isAnInteger = int.TryParse(str, out element);
}
nummer[i] = element;
}
Use the int.TryParse method.
This code reads the trimmed input string from the user and tries to convert it to an integer. If the conversion is successful, it creates an integer variable called "result" which you can then use in the IF block. If the conversion fails, you can write the code for what you want to happen in the ELSE block. If you need a total of 10 integers in the list, I would drop the FOR loop in favor of a DO WHILE loop that checks for how many integers were successfully converted and added to the list. It will keep requesting input until the list is filled with 10 integers.
List<int> elements = new List<int>();
do
{
Console.WriteLine("Please enter an integer.");
if (int.TryParse(Console.ReadLine().Trim(), out int result))
{
Console.WriteLine($"You entered the integer {result}");
elements.Add(result);
}
else
{
Console.WriteLine("You must enter an integer. Please try again.");
}
} while (elements.Count < 10);
If you want to keep your code with the try catch loop here it is:
for (int i = 0; i < nummer.Length; i++)
{
try {
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
int element = Convert.ToInt32(str);
nummer[i] = element;
}
catch
{
MessageBox.Show("Error, numbers only");
goto breakloop;
}
}
breakloop:;
The goto statement ends the loop if an error occured
It's a good idea to not throw exceptions at all if you can help it. In this case, you can use int.TryParse() instead. This block of code can replace your one int element... line:
int element;
if (!int.TryParse(str, out element)) {
Console.WriteLine("Bad!!");
i--;
continue;
}
The i-- is to make sure that i has the same value on the next interaction of the loop. Doing that will make sure you still get 10 valid inputs before you finish the loop. (Many will say this is a really bad thing to do, but the reason for that is readability - if you have a large for loop and decrement the value somewhere in the middle, it makes it difficult for the next guy looking at your code to understand exactly what's going on. But this is a short loop, so it's pretty obvious. Just be aware of this.)
The continue keyword skips the rest of that iteration of the loop and moves on to the next (so you don't add the bad value to your array).

not all code paths return a value? help needed

I am making a c# console board game and I am having trouble trying to sort out this error that is currently linked to the static int ResetGame() part. Apparently not all code paths return a value. How do I fix this?
static int ResetGame()
{
Console.WriteLine("Welcome to Tactical Space Cheese Racer");
Console.WriteLine("");
Console.WriteLine("Press any Key to continue");
Console.ReadLine();
Console.Clear();
Console.WriteLine("Please enter the number of players that wish to play (2-4) : ");
int NoOfPlayers = int.Parse(Console.ReadLine());
Console.WriteLine("");
for (int i = 0; i < NoOfPlayers; i++)
{
Console.WriteLine("");
Console.WriteLine("Please enter the name of the player: " + i + i++);
Console.WriteLine("");
players[i].Name = Console.ReadLine();
players[i].Pos = 0;
}
}
I have more code available if you need to see it to resolve the problem
The problem you have is that your method should return an int and you don't return it.
If you don't want to return anything, then you should state that your method is a void method.
static void ResetGame()
{
}
As I can conclude from your code, this might was your intention. So making your method a void one, you will not have any problem.
Furthermore, I have to make a side note about the way you set the number of players. If the user enters a non integere value you will get an exception, that you don't handle. In addition to this, if the user enters an integer greater than 4, that shouldn't be ok. That being said you should take care both of the above.
int numberOfPlayers = -1;
Console.WriteLine("Please enter the number of players that wish to play (2-4) : ");
// The method Int32.TryParse parses the input and check if it
// can be represented as a 32-bit integer number.
// If parse succeeds, then the value is assigned to numberOfPlayers
// and the method returns true. Otherwise, it returns false.
while(!Int32.TryParse(Console.ReadLine()), out numberOfPlayers) &&
!(numberOfPlayers>2 && numberOfPlayers<4))
{
Console.WriteLine("Please enter a valid number between (2-4): ");
}
update
Idle_Mind pointed out in his comment the following:
I would say he needs to Return the Number of Players.
If that's the case, you just simple have to add this before the closing curly brace of your method:
return numberOfPlayers;
I suppose that you will keep my naming. If you will keep yours just change the name of the variable to yours.

C#- Getting user input for Age.. but receiving error?

I am trying to make improve my programming and getting things drilled into my head so I'm just quickly developing an application that gets user's input and prints their name. But also gets their input for "Age verification".
I'm practicing IF & ELSE statements as well as nesting classes.
However my compiler is shooting me an error and I just cannot seem to figure it out. I'm trying to get the user to input his age, and then proceed with the IF & ELSE statement.
Compiler is shooting error that . ""Cannot implicitly convert type
string to int"
The only error in the program right now is the
myCharacter.age = Console.ReadLine();
using System;
namespace csharptut
{
class CharPrintName
{
static void Main()
{
Character myCharacter = new Character();
Console.WriteLine("Please enter your name to continue: ");
myCharacter.name = Console.ReadLine();
Console.WriteLine("Hello {0}!", myCharacter.name);
Console.WriteLine("Please enter your age for verification purposes: ");
myCharacter.age = Console.ReadLine();
if (myCharacter.age <= 17)
{
Console.WriteLine("I'm sorry {0}, you're too young to enter!",myCharacter.name);
}
else if (myCharacter.age >= 18)
{
Console.WriteLine("You can enter!");
}
}
}
class Character
{
public string name;
public int age;
}
}
As the error says you can't implicitly type a string to an int. You need to parse it into an int.
string input = Console.ReadLine();
int age;
if (int.TryParse(input, out age)
{
// input is an int
myCharacter.age = age;
}
else
{
// input is not an int
}
You are trying to assign a string value to an int with this line:
myCharacter.age = Console.ReadLine();
Try:
myCharacter.age = Int32.Parse(Console.ReadLine());
character.age expects an Int but ReadLine() returns a string, you need to look at using int.Parse or int.TryParse to avoid exceptions
e.g.
if (!int.TryParse(Console.ReadLine(),out myCharacter.age)) {
Console.WriteLine("You didn't enter a number!!!");
} else if (myCharacter.age <= 17) {
Console.WriteLine("I'm sorry {0}, you're too young to enter!",myCharacter.name);
} else {
Console.WriteLine("You can enter!");
}
This looks like a student project.
The input coming from the ReadLine() is always of type string. You're then comparing a string to 17 which isn't valid, as 17 is an int. Use TryParse versus parse to avoid throwing an exception at runtime.
string typedAge = Console.ReadLine();
int Age = 0;
if (!int.TryParse(typedAge, out Age))
Console.WriteLine("Invalid age");
if (Age <= 17)
Console.WriteLine("You're awfully young.");
OK. The problem here is that the age is defined as an int and Console.ReadLine() always returns a string so thus you have to convert the user input from string to integer in order to correctly store the age.
Something like this:
myCharacter.age = Int32.Parse(Console.ReadLine());
When you read input from the console, it returns it to you in the form of a string. In C#, which is a statically typed language, you cannot simply take one type and apply it to another type. You need to convert it somehow, there are several ways to do this.
The first way would be casting:
myCharacter.age = (int)Console.ReadLine();
This won't work because a string and an integer are two completely different types and you can't simply cast one to the other. Do some reading on casting types for more information.
The second way would be to convert it, again there are a couple of ways to do this:
myCharacter.age = Int32.Parse(Console.ReadLine());
This will work as long as you type in an actual number, in this case the Parse method reads the string and figures out what the appropriate integer is for you. However, if you type in "ABC" instead, you will get an exception because the Parse method doesn't recognize that as an integer. So the better way would be to:
string newAge = Console.ReadLine();
int theAge;
bool success = Int32.TryParse(newAge, out theAge);
if(!success)
Console.WriteLine("Hey! That's not a number!");
else
myCharacter.age = theAge;
In this case the TryParse method tries to parse it, and instead of throwing an exception it tells you it can't parse it (via the return value) and allows you to handle that directly (rather than thru try/catch).
That's a little verbose, but you said you're learning so I thought I'd give you some stuff to consider and read up on.

Convert String to int in C#

I am trying to write a simple program that asks the user to enter a number and then I will use that number to decide what the cost of the ticket will be for their given age. I am having trouble when trying to convert the string to int. Otherwise the program layout is fine. Any suggestions?
thanks
using System;
class ticketPrice
{
public static void Main(String[] args)
{
Console.WriteLine("Please Enter Your Age");
int input = Console.ReadLine();
if (input < 5)
{
Console.WriteLine("You are "+input+" and the admisson is FREE!");
}
else if (input > 4 & input < 18)
{
Console.WriteLine("You are "+input+" and the admission is $5");
}
else if (input > 17 & input < 56)
{
Console.WriteLine("You are "+input+" and the admission is $10");
}
else if (input > 55)
{
Console.WriteLine("You are "+input+" and the admission is $8");
}
}
}
Try the int.TryParse(...) method. It doesn't throw an exception.
http://msdn.microsoft.com/en-us/library/f02979c7.aspx
Also, you should use && not & in your conditions. && is logical AND and & is bitwise AND.
For easy parsing of strings to integers (and other number types), use that number type's .TryParse(inputstring, yourintegervariable) method. This method will output a Boolean (True/False), letting you know whether the operation passed or failed. If the result is false, you can give an error message before going any further (don't have to worry about crashing your program).
Previous text concerning switch statements has been removed
In C#, you need to use the && operator for logical AND. & is not the same and may not work the way you believe it will.
I suggest to use the Int32.TryParse() method. Further I suggest to refactor your code - you can make it much cleaner (assuming this is not just example code). One solution is to use a key value pair list to map from age to admission.
using System;
using System.Collections.Generic;
using System.Linq;
static class TicketPrice
{
private static readonly IList<KeyValuePair<Int32, String>> AgeAdmissionMap =
new List<KeyValuePair<Int32, String>>
{
new KeyValuePair<Int32, String>(0, "FREE!"),
new KeyValuePair<Int32, String>(5, "$5."),
new KeyValuePair<Int32, String>(18, "$10."),
new KeyValuePair<Int32, String>(56, "$8.")
};
public static void Main(String[] args)
{
Console.WriteLine("Please Enter Your Age!");
UInt32 age;
while (!UInt32.TryParse(Console.ReadLine(), out age)) { }
String admission = TicketPrice.AgeAdmissionMap
.OrderByDescending(pair => pair.Key)
.First(pair => pair.Key <= age)
.Value;
Console.WriteLine(String.Format(
"You are {0} and the admission is {1}",
age,
admission));
}
}
I used an unsigned integer to prevent entering negative ages and put the input into a loop. This way the user can correct an invalid input.
int number = int.Parse(Console.ReadLine());
Be aware that this will throw an exception if they enter an invalid number.
The first thing you need to do is change your input variable to a string:
string input = Console.ReadLine();
Once you have that, there are several ways to convert it to an integer. See this answer for more info:
Better way to cast object to int

Categories

Resources