first time posting and have a question about if statements with methods.
I have been trying multiple ways of doing this and haven't gotten it to work. I am trying to call methods based on if the user types a number between 1 and 6. This is what I got so far, please don't judge the dialogue of the calculator (I'm only 14).
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Work());
}
public static void Work(int input)
{
if (input < 0)
{
Console.WriteLine("Please enter a number between 1 and 6");
}
else if (input == 1)
{
Console.WriteLine(Add());
}
else if (input == 2)
{
Console.WriteLine(Subtract());
}
}
public static int Add()
{
Console.WriteLine("Hey bro, need a new number man!");
string input1 = Console.ReadLine();
Console.WriteLine("Gnarly dude, how 'bout a second one?");
string input2 = Console.ReadLine();
Console.WriteLine("Here botine-shake, there is your final number.");
int num1 = int.Parse(input1);
int num2 = int.Parse(input2);
int result = num1 + num2;
return result;
}
public static int Subtract()
{
Console.WriteLine("Number. Now. Please hurry.");
string input1 = Console.ReadLine();
Console.WriteLine("Need another number. Hurry.");
string input2 = Console.ReadLine();
Console.WriteLine("Here is your number. Now please leave.");
int num1 = int.Parse(input1);
int num2 = int.Parse(input2);
int result = num1 - num2;
return result;
}
public static int Multiply()
{
Console.WriteLine("Gimme that number.");
string input1 = Console.ReadLine();
Console.WriteLine("Ok, how would you like to give me another?");
string input2 = Console.ReadLine();
Console.WriteLine("Here you go baby.");
int num1 = int.Parse(input1);
int num2 = int.Parse(input2);
int result = num1 * num2;
return result;
}
public static decimal Divide()
{
Console.WriteLine("/enter.Num1");
string input1 = Console.ReadLine();
Console.WriteLine("/enter.Num2");
string input2 = Console.ReadLine();
Console.WriteLine("/final.Dividend");
decimal num1 = decimal.Parse(input1);
decimal num2 = decimal.Parse(input2);
decimal result = num1 / num2;
return result;
}
public static int Square()
{
Console.WriteLine("What number do you want SQUARED?");
string input1 = Console.ReadLine();
Console.WriteLine("Here's your square!");
int num1 = int.Parse(input1);
int result = num1 * num1;
return result;
}
public static int Cube()
{
Console.WriteLine("What have thine want CUBED?");
string input1 = Console.ReadLine();
Console.WriteLine("Here, I bestow upon you your cube...");
int num1 = int.Parse(input1);
int result = num1 * num1 * num1;
return result;
}
}
I didn't quite understand what you mean, but there should be something needs to be fixed:
static void Main(string[] args)
{
Console.WriteLine(Work());
}
public static void Work(int input)
......
You can see the Work() is an "Action", not a "Function". Because it returns nothing, so it's not appropriate to WriteLine the result from Work()
By the way, you can see the Work(int input) needs an input, which obviously you didn't provide.
Try This:
static void Main(string[] args)
{
int myInput = int.Parse(Console.ReadLine());
Work(myInput);
}
public static void Work(int input)
{ .....
From the code that you provided it looks like you're not asking for user input before calling your Work method, so nothing will happen since there is no argument being passed to the Work method.
You should try something like this:
static void Main(string[] args)
CaptureUserInput();
}
public static void WriteInstructions() {
Console.WriteLine("Enter a number between 1 and 6 to perform a calculation");
// instruct the user for each available operation
Console.WriteLine("1: Addition");
Console.WriteLine("2: Subtraction");
}
public static void CaptureUserInput() {
WriteInstructions();
// capture the user's input and convert it to an integer
string stringInput = Console.Readline();
int input = int.Parse(stringInput);
// validate that it is a valid integer
if (Enumerable.Range(1,6).Contains(input)) {
// this is a valid number in the range we want, call the Work method
Work(input);
} else {
// the user has entered an invalid entry, prompt them and wait for another attempt
Console.WriteLine("Sorry, that is an invalid option.");
CaptureUserInput();
}
}
Note that this is setup so that you can recursively handle when a user enters something that that's not a number or outside the range from 1 - 6. This will prompt the user they entered something invalid and then wait for the next attempt to enter a number.
Related
namespace ConsoleApp4
{
class Program
{
public static int Year(int num1)
{
Console.WriteLine("Enter a year.");
num1 = Convert.ToInt32(Console.ReadLine());
if (num1 % 4 == 0)
{
Console.WriteLine("This is a leap year mate.");
Console.ReadLine();
}
return num1;
}
static void Main(string[] args)
{
Console.WriteLine(Year());
Console.ReadLine();
}
}
}
You have an unnecessary parameter on public static int Year(int num1) ... you don't need int num1 because you don't even use it. But the error message is because you called Year without giving it a parameter. Your parenthesis were empty:
Year()
It would work if you used Year(0) or gave it some kind of other int parameter, but as you're not even using the parameter you should delete it:
public static int Year() { /* ... your code here */ }
But your error message is what you get whenever you try to call methods or constructors without supplying the proper arguments.
You don't need an input parameter in Year method. Remove it and try this
public static int Year()
{
Console.WriteLine("Enter a not leap year.");
var num1 = Convert.ToInt32(Console.ReadLine());
while (num1 % 4 == 0)
{
Console.WriteLine("This is a leap year mate. Try again");
num1 = Convert.ToInt32(Console.ReadLine());
}
return num1;
}
static void Main(string[] args)
{
Console.WriteLine(Year());
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
I don't really understand arrays and I need to create a variable of type 'array of songs' then initialize it to a new Array so it can store 4 references to Songs. How would I then create a loop that would run enough times to fill the array whilst calling the InputSOngDetails() method and store the return value in that method?
namespace Songs
{
class Program
{
static void Main(string[] args) {
InputSongDetails();
}
static Song InputSongDetails()
{
Console.WriteLine("What is the name of your song");
string name = Console.ReadLine();
Console.WriteLine("What is the artists name");
string artist = Console.ReadLine();
int records;
Console.WriteLine("How many records did it sell");
while (!int.TryParse(Console.ReadLine(), out records) || records < 0)
{
Console.WriteLine("That is not valid please enter a number");
}
return new Song(name, artist, records);
}
}
}
This is my Songs class if needed
namespace Songs
{
class Song
{
string name;
string artist;
int copiesSold;
public Song(string name, string artist, int copiesSold)
{
this.name = name;
this.artist = artist;
this.copiesSold = copiesSold;
}
public Song()
{
}
public string GetArtist()
{
return artist;
}
public string GetDetails()
{
return $"Name: {name} Artist: {artist} Copies Sold: {copiesSold},";
}
public string GetCertification()
{
if (copiesSold<200000)
{
return null;
}
if (copiesSold<400000)
{
return "Silver";
}
if (copiesSold<600000)
{
return "gold";
}
return "Platinum";
}
}
}
Fist, initialize your array of songs with new Song[ length ], then a simple for-loop will suffice.
static void Main(string[] args)
{
Song[] songs = new Song[4];
for(int i = 0; i < songs.Length; i++)
{
songs[i] = InputSongDetails();
}
}
Or as the commenters suggest, just use a variable-length List<Song>.
static void Main(string[] args)
{
List<Song> songs = new List<Song>();
for(int i = 0; i < 4; i++)
{
songs.Add(InputSongDetails());
}
}
Once you've mastered the basics, you can also accomplish this with a bit of Linq (though I wouldn't actually recommend it in this case):
static void Main(string[] args)
{
var songs = Enumerable.Range(0, 4)
.Select(i => InputSongDetails())
.ToList();
}
This is not really an answer as much as it is a tip for getting input from the user in a console application which might be useful to you (well, the answer is in the last code snippet, but p.s.w.g has already covered that very well).
Since an interactive console session usually ends up with a lot of Console.WriteLine("Ask the user a question"); string input = Console.ReadLine();, and, as you've already done very well, include some validation on the input in some cases, I've found it handy to write the following methods below.
Each of them take in a string, which is the prompt for the user (the question), and return a strongly-typed variable that represents their input. Validation (when needed) is all done in a loop in the method (as you've done):
private static ConsoleKeyInfo GetKeyFromUser(string prompt)
{
Console.Write(prompt);
var key = Console.ReadKey();
Console.WriteLine();
return key;
}
private static string GetStringFromUser(string prompt)
{
Console.Write(prompt);
return Console.ReadLine();
}
public static int GetIntFromUser(string prompt = null)
{
int input;
int row = Console.CursorTop;
int promptLength = prompt?.Length ?? 0;
do
{
Console.SetCursorPosition(0, row);
Console.Write(prompt + new string(' ', Console.WindowWidth - promptLength - 1));
Console.CursorLeft = promptLength;
} while (!int.TryParse(Console.ReadLine(), out input));
return input;
}
With these methods in place, getting input is as simple as:
string name = GetStringFromUser("Enter your name: ");
int age = GetIntFromUser("Enter your age: ");
And it makes writing the method to get a Song from the user that much easier:
private static Song GetSongFromUser()
{
return new Song(
GetStringFromUser("Enter song name: "),
GetStringFromUser("Enter Artist name: "),
GetIntFromUser("Enter number of copies sold: "));
}
So now our main method just looks like (and this is the answer to your question):
private static void Main()
{
var songs = new Song[4];
for (int i = 0; i < songs.Length; i++)
{
songs[i] = GetSongFromUser();
}
Console.WriteLine("\nYou've entered the following songs: ");
foreach (Song song in songs)
{
Console.WriteLine(song.GetDetails());
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Additionally, here are some suggestions for improving the Song class.
So Im learning basic C# and wonders how I can return x and y from AGE(); and NUMBER(); and use those variables in Name();
Right now x and y in the Name(); parameters are understandably wrong since there are no local variables in the constructor. But I returned x and y from the function. So how can I use them in the Name function?
namespace CSharp_001
{
class Program
{
public Program()
{
Name(x, y);
AGE();
NUMBER();
}
public int AGE()
{
int x;
Console.WriteLine(" And enter age: ");
x = Console.Read();
return x;
}
public int NUMBER()
{
int y;
Console.WriteLine(" And favorite number: ");
y = Console.Read();
return y;
}
public void Name(int x, int y)
{
Console.WriteLine("Enter your name: ");
string test = Console.ReadLine();
Console.WriteLine("Hi " + test);
}
static void Main(string[] args)
{
new Program();
Console.ReadLine();
}
}
}
In c#, the Type of a value is really important. When you read from the console, you get a string. However, your Age() and NUMBER() functions return ints. A function that is declared to return an int cannot return a string. You need to convert those values to int before you can return them:
public int AGE() {
Console.WriteLine(" And enter age: ");
return int.Parse(Console.Read());
}
After you fix both functions, you can call Name() like this:
public Program()
{
int x = AGE();
int y = NUMBER();
Name(x, y);
}
or like this:
public Program()
{
Name(AGE(), NUMBER());
}
In either case, if you want to pass those values to the Name() function, the calls to AGE() and NUMBER() must be resolved before the the call to Name(). The console text indicates you want the prompts in Name() to come first. In that case, you might do this:
public void Name()
{
Console.WriteLine("Enter your name: ");
string test = Console.ReadLine();
Console.WriteLine("Hi " + test);
int age = AGE();
int number = NUMBER();
}
public Program()
{
Name();
}
For educational purposes:
public Program()
{
var age = AGE();
var num = NUMBER();
Name(age, num);
}
When a function returns a value, you need to store it or use it immediately. If you look at your example, in the AGE method, you have
x = Console.Read();
Console.Read is returning the value you're storing in x. But this x is local to the AGE method, nothing else called x will have that value (its scope is local to the AGE method). The AGE method returns this value, but that doesn't mean you can use the variable x anywhere else.
When you call AGE in the Program constructor, you need to save its return value. If you have that value saved, then you can pass it in as an argument to Name.
int age = AGE();
Name(age, y);
(assuming y is set by your call to NUMBER). When Name is called, you'll be able to use x, and it will have the value you passed in (which above, is called age).
A few comments:
Console.Read only read one character and returns the UTF-16 code of that character - you should use Console.ReadLine instead and parse the results if necessary.
Functions should be named to describe what they do, so GetAge and GetName would be more appropriate function names
Constructors should only be used to initialize the object to a usable state. Your code should either be in the Main function or in a separate function of Program that Main calls.
variables should have meaningful names. x and y do not give any indication of what they represent.
So something like this would be more appropriate:
class Program
{
public void Run()
{
int age = GetAge();
int number = GetNumber();
GetName(age, number);
}
public int GetAge(){
string age;
Console.WriteLine(" And enter age: ");
age = Console.ReadLine();
return int.Parse(x); // or TryParse and loop until the parse succeeds
}
public int GetNumber(){
string number;
Console.WriteLine(" And favorite number: ");
number = Console.ReadLine();
return int.Parse(number); // or TryParse and loop until the parse succeeds
}
public void Name(int x, int y)
{
Console.WriteLine("Enter your name: ");
string test = Console.ReadLine();
Console.WriteLine("Hi " + test);
}
static void Main(string[] args) {
new Program().Run();
Console.ReadLine();
}
}
How would I write another function named noNegatives for this code? I want to rewrite the code with another function named noNegatives but I still want the program to do the same thing.
class Program
{
static void Main(string[] args)
{
string numberIn;
int numberOut;
numberIn = Console.ReadLine();
while (!int.TryParse(numberIn, out numberOut) || numberOut < 0)
{
Console.WriteLine("Invalid. Enter a number that's 0 or higher.");
numberIn = Console.ReadLine();
}
}
}
static void Main(string[] args)
{
int number = NoNegatives();
}
static int NoNegatives()
{
int numberOut;
string numberIn = Console.ReadLine();
while (!int.TryParse(numberIn, out numberOut) || numberOut < 0)
{
Console.WriteLine("Invalid. Enter a number that's 0 or higher.");
numberIn = Console.ReadLine();
}
return numberOut;
}
Follwing is the simplest way you can write it
static void Main(string[] args)
{
int retVal=0;
string numberIn;
int numberOut;
numberIn = Console.ReadLine();
while(noNegatives(numberIn,numberOut)=0)
{
}
}
int noNegatives(String numberIn,int numberOut)
{
numberIn = Console.ReadLine();
if (!int.TryParse(numberIn, out numberOut) || numberOut < 0)
{
Console.WriteLine("Invalid. Enter a number that's 0 or higher.");
return 0;
}
else
{
return 1;
}
}
This question is very similar to the one posted here.
static void Main(string[] args)
{
string numberIn = Console.ReadLine();
int numberOut;
while(!IsNumeric(numberIn))
{
Console.WriteLine("Invalid. Enter a number that's 0 or higher.");
numberIn = Console.ReadLine();
}
numberOut = int.Parse(numberIn);
}
private static bool IsNumeric(string num)
{
return num.ToCharArray().Where(x => !Char.IsDigit(x)).Count() == 0;
}
Since the negative sign is not a digit, IsNumeric will return false for negative numbers.
Coming from a procedural background, I'm running into a conceptual block while designing a menu-based console application and user input validation. My goal is to display a menu that launches other processes. I want to limit user input to 1, 2, or 3 at the menu.
In a procedural language, I would do something like this pseudocode:
10 print "Make a choice"
20 choice = [dataFromKeyboard]
30 if choice < 4 && choice > 0
40 then 10
50 else 60
60 process valid choices
and no matter what I try, I can't get that out of my head while designing an OO program. Consider (simplified to include only 3 menu items):
class Menu
{
public static void Main(String[] args)
{
DisplayMenu thisdm = new DisplayMenu;
int menuChoice = thisdm.displayMenu();
ProcessMenu thispm = new ProcessMenu();
thispm.processMenu(menuChoice);
}
}
class DisplayMenu
{
public int displayMenu()
{
Console.WriteLine("1 - foo3");
Console.WriteLine("2 - foo2");
Console.WriteLine("3 - foo3");
Console.WriteLine("choose");
String choice = Console.ReadLine();
int intChoice = Convert.ToInt32(choice);
return intChoice;
}
}
class ProcessMenu
{
public void processMenu(int choice)
{
switch(choice)
{
case 1:
foo1();
break;
case 2:
foo2();
break;
case 3:
foo3();;
break;
default:
Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
break;
}
}
}
So here's where I'm stuck. I just can't wrap my head around a simple and elegant way validate my user input that's from an OO rather than procedural standpoint.
Assuming I do the validation in the DisplayMenu, I would be validating after the input is read. But if it turns out to be invalid, how do I re-ask for valid input, since I've already called displayMenu method from Main?
I've been playing with while loops for about an hour, something like this:
intChoice = 0;
[print the menu]
while ((intChoice<1) || (intChoice>3))
Console.WriteLine("Please make a valid choice from the menu");
choice = Console.ReadLine();
etc.
but can't seem to find the sweet spot where I can control user input.
I suspect it's because I'm thinking to procedurally, and not object-oriented enough. Anyone have any tips or input to help me wrap my head around this?
Expanding on #AlexeiLevenkov's suggestion of "turning your classes 90 degrees", I went a step further and created this example of a "Modular" console Application:
class Program
{
static void Main(string[] args)
{
//Retrieve all Module types in the current Assembly.
var moduletypes = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.IsSubclassOf(typeof(ConsoleModule)));
//Create an instance of each module
var modules = moduletypes.Select(Activator.CreateInstance)
.OfType<ConsoleModule>()
.OrderBy(x => x.Id)
.ToList();
int SelectedOption = -1;
while (SelectedOption != 0)
{
//Show Main Menu
Console.Clear();
Console.WriteLine("Please Select An Option:\n");
modules.ForEach(x => Console.WriteLine(string.Format("{0} - {1}", x.Id, x.DisplayName)));
Console.WriteLine("0 - Exit\n");
int.TryParse(Console.ReadLine(), out SelectedOption);
//Find Module by Id based on user input
var module = modules.FirstOrDefault(x => x.Id == SelectedOption);
if (module != null)
{
//Execute Module
Console.Clear();
module.Execute();
Console.WriteLine("Press Enter to Continue...");
Console.ReadLine();
}
}
}
ConsoleModule class:
public abstract class ConsoleModule
{
public int Id { get; set; }
public string DisplayName { get; set; }
public abstract void Execute();
}
Some sample Modules:
public class EnterUserNameModule : ConsoleModule
{
public EnterUserNameModule()
{
Id = 2;
DisplayName = "User Name";
}
public static string UserName { get; set; }
public override void Execute()
{
Console.WriteLine("Please Enter Your Name: ");
UserName = Console.ReadLine();
}
}
public class HelloWorldModule: ConsoleModule
{
public HelloWorldModule()
{
Id = 1;
DisplayName = "Hello, World!";
}
public override void Execute()
{
Console.WriteLine("Hello, " + (EnterUserNameModule.UserName ?? "World") + "!");
}
}
public class SumModule: ConsoleModule
{
public SumModule()
{
Id = 3;
DisplayName = "Sum";
}
public override void Execute()
{
int number = 0;
Console.Write("Enter A Number: ");
if (int.TryParse(Console.ReadLine(), out number))
Console.WriteLine("Your number plus 10 is: " + (number + 10));
else
Console.WriteLine("Could not read your number.");
}
}
Result:
It uses a little bit of reflexion to find all types deriving from ConsoleModule in the current assembly, then shows a menu with all these options (which are actually properties in this class), and calls the Execute() method when an appropiate option is selected. Much more towards OO way of thinking.
Make your processMenu function return some kind of indicator. You could use exceptions for this instead, but that's overkill.
public bool processMenu(int choice)
{
....
}
If the choice was acceptable, then return true, otherwise return false. Then:
public static void Main(String[] args)
{
DisplayMenu thisdm = new DisplayMenu;
ProcessMenu thispm = new ProcessMenu();
int menuChoice;
do {
menuChoice = thisdm.displayMenu();
} while( !thispm.processMenu(menuChoice) );
}
The way you are doing should be changed. Anyhow, for the same as your question, this works out:
DisplayMenu thisdm = new DisplayMenu();
int menuChoice = -1;
while (menuChoice < 1 || menuChoice > 3)
{
Console.WriteLine("enter valid choice");
menuChoice = thisdm.displayMenu();
}
ProcessMenu thispm = new ProcessMenu();
thispm.processMenu(menuChoice);
the code like:
class Program
{
static void Main(string[] args)
{
DisplayMenu thisdm = new DisplayMenu();
ProcessMenu thispm = new ProcessMenu();
thisdm.displayMenu();
int menuChoice = thispm.GetChoice();
thispm.processMenu(menuChoice);
Console.Read();
}
}
class DisplayMenu
{
public void displayMenu()
{
Console.WriteLine("1 - foo3");
Console.WriteLine("2 - foo2");
Console.WriteLine("3 - foo3");
Console.WriteLine("choose");
}
}
class ProcessMenu
{
public int GetChoice()
{
String choice = Console.ReadLine();
int intChoice = Convert.ToInt32(choice);
while (!Validate(intChoice))
{
Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
choice = Console.ReadLine();
intChoice = Convert.ToInt32(choice);
}
return intChoice;
}
public void processMenu(int choice)
{
switch (choice)
{
case 1:
//foo1();
break;
case 2:
//foo2();
break;
case 3:
//foo3(); ;
break;
default:
//Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
break;
}
}
private int[] forChoices=new int[]{1,2,3};
private bool Validate(int choice)
{
if(forChoices.Contains(choice))
{
return true;
}
return false;
}
}