calling 2 input values from a method - c#

I have been trying to work this concept out for days. I have a console program with 3 classes :
1) Main program
2) Create Login screen
3) Actual Login screen
Here is the code:
class Program
{
static void Main(string[] args)
{
//Instantiate Main Menu
Menu myMenu = new Menu();
myMenu.mainMenu();
//testing global values
Login myLogin = new Login();
Console.Write("The new Login is ");
Console.WriteLine(myLogin.newLogin);
//Pause
Console.WriteLine("Press Any Key...");
Console.ReadLine();
}
}
class Menu
{
public void mainMenu()
{
// [create menu that prints choices on the screen]
start:
Console.Clear();
Console.WriteLine("PLEASE CHOOSE AN OPTION");
Console.WriteLine();
Console.WriteLine("[1] LOGIN \n[2] CREATE LOGIN");
Console.WriteLine();
Console.Write("> ");
string menuChoice = Console.ReadLine();
// [switch/case for Main Menu]
switch (menuChoice)
{
case "1":
Console.WriteLine("You chose 1");
break;
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
myLogin.createLogin();
Console.WriteLine(myLogin.newLogin);
break;
default:
Console.WriteLine("INVALID OPTION... TRY AGAIN.");
System.Threading.Thread.Sleep(5000);
goto start;
}
}
class Login
{
// [empty containers for newLogin & newPass]
public string newLogin { get; set; }
public string newPass { get; set; }
public void createLogin()
{
// [display new login screen & assign newLogin & newPass]
Console.Clear();
Console.WriteLine("CREATE NEW LOGIN");
Console.WriteLine();
Console.Write("LOGIN: ");
newLogin = Console.ReadLine();
Console.Write("PASSWORD: ");
newPass = Console.ReadLine();
// [instantiate & return to main menu]
Menu myMenu = new Menu();
myMenu.mainMenu();
}
}
Now when I try to output the code from main program the value is null. Do I have the wrong structure here? I dont really need to store more than one login and pass (for now) so an array is not needed at this point, but im sure ill learn that down the road. I am self learning so I am trying to keep things as simple as I can until I nail the concept.
I want to store the newLogin and newPass and print the values in main. Please help.
Thanks
Mike

In this code:
.....
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
Console.WriteLine(myLogin.newLogin); //WRITE TO CONSOLE
myLogin.createLogin(); // QUERY AFTER WRITE
......
You first write an emtpy login, and after only query for it. So it's "normal" that you don't see any login information on the scree, as it printed before it was intitialized and after never printed again.
To resolve this, just invert function calls:
.....
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
myLogin.createLogin(); // QUERY
Console.WriteLine(myLogin.newLogin); //WRITE TO CONSOLE
...
EDIT
If you want to operate over Login, one of possible solutions is:
class Menu
{
private Login _login = new Login(); // EVERYWHERE IN MENU USE THIS FIELD, THE SAME INSTANCE
.....
case "2":
// [instantiate createLogin]
//Login myLogin = new Login(); NO MORE NEW INSTANCE BUT USE ALREADY AVAILABLE ONE
_login.createLogin(); // QUERY
Console.WriteLine(_login .newLogin); //WRITE TO CONSOLE
...
}

Are you sure it's showing up as null in Main()? You're also printing myLogin.newLogin in your Menu switch/case. When you print it in your Menu, you're printing it before calling myLogin.createLogin() so it should be null, but by the time it gets back to Main() it should be set correctly.

I found an answer. It may not be the best, but it works. Once I corrected the Query/Write problem (listed above) I started thinking more about instances and realized that BY CREATING THE NEW INSTANCE I AM IN FACT CLEARING THE DATA. Sorry for the caps but my intent is to help some other self learner.
Ok so in theory I want to keep the createLogin method once its called in the case. How do I keep it? I made the createLogin, newLogin, and newPass classes static so that the value can be assigned and the class can then be called from main. By calling it without instantiating it, it keeps the value assigned.
class Login
{
// [empty containers for newLogin & newPass]
public static string newLogin { get; set; }
public static string newPass { get; set; }
public static void createLogin()
{
// [display new login screen & assign values]
Console.Clear();
Console.WriteLine("CREATE NEW LOGIN");
Console.WriteLine();
Console.Write("LOGIN: ");
newLogin = Console.ReadLine();
Console.Write("PASSWORD: ");
newPass = Console.ReadLine();
// [instantiate & return to main menu]
//Menu myMenu = new Menu();
//myMenu.mainMenu();
}
and in main:
//testing global values
Console.Write("The new Login is ");
Console.WriteLine(Login.newLogin);
This works, thanks everyone for contributing. It was with others comments that I was able to figure this one out. Hope my solution is clear for someone else. Peace.

Related

C#--Why do I have to hit enter twice to commit Console.Readline

C# newbie. Trying to make a simple gradebook program where user:
Enters names of students until 'done' is entered
Enter grades for each user, then calculate average
Part 2 works, but my problem is with part one--you have to hit enter twice to commit the name to the list. For instance, if I enter Bob, Lisa, Kevin, Jane--only Bob and Kevin would make it in--the second line (even if you type something) acts as the line where the console.read is committed to the list.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Csharp
{
class MainClass
{
static List<string> mylist = new List<string> { };
public static void Main(string[] args)
{
UserInput();
GradeEnter();
}
public static void UserInput()
{
Console.WriteLine("Enter Some names (type 'done' when finished)");
do
{
mylist.Add(Console.ReadLine());
} while (!Console.ReadLine().Equals("done"));
}
public static void GradeEnter()
{
foreach (var x in mylist)
{
List<int> myInts = new List<int>();
Console.WriteLine("\nEnter grades for {0}, (enter any letter when done)", x);
while (Int32.TryParse(Console.ReadLine(), out int number))
{
myInts.Add(number);
}
Console.Write("Average is ");
Console.Write(myInts.Average());
}
}
}
}
Any help on this would be much much appreciated!
Thanks
You are calling ReadLine twice.
You can try this instead:
public static void UserInput()
{
Console.WriteLine("Enter Some names (type done to exit)");
string name = Console.ReadLine();
while (!name.Equals("done"));
{
mylist.Add(name);
name = Console.ReadLine();
}
}
Another way of doing the same
public static void UserInput()
{
Console.WriteLine("Enter Some names (type done to exit)");
while (true);
{
string name = Console.ReadLine();
if (name == "done")
{
// This will stop the while-loop
break;
}
mylist.Add(name);
}
}
Now let's analyze what your code is doing
do
{
// Read line and add it to the list. Even if the user writes "done"
mylist.Add(Console.ReadLine());
// Read the console again, if the user enters done, exit. But if the user enters other name, you are discarding it, you are not adding it to the list
} while (!Console.ReadLine().Equals("done"));
Some test cases using your code:
1. Peter <- gets added to the list
2. Lucas <- does not get added to the list, just checks if it is done
3. Mario <- gets added to the list
4. Juan <- again, just checking if it is done, so not added to the list
5. done <- It is treated like a name, so it will be added to the list
6. done <- now it will finish :)
Read name once and then either add it to myList or stop looping:
public static void UserInput() {
Console.WriteLine("Enter Some names (type done to exit)");
for (string name = Console.ReadLine(); !name.Equals("done"); name = Console.ReadLine())
mylist.Add(name);
}
Thanks for everyone's help. I ended up using a combination of while(true) and an if statement:
Console.WriteLine("Enter some names (type 'done' when finished)");
do
{
string name = Console.ReadLine();
if (!name.Equals("done"))
{
mylist.Add(name);
}
else
break;
} while (true);

Do not check in the generic list of a item there is

I wish to make a small insurance application. The application asks your name and then checks if name already exists; if they exist then you get a message this name is already used.
if not then you will be asked what for insurance do you want and then on the screen you get a message the name is correctly signed up.
and i have a function that lists all my client's names and the kind of insurance as a generic list
I make a generic list and in my function i use foreach so i can print every item in the generic list everything works good but if i add a person to my list and i try back and write the same name i don't get error.
Question: Why I don't get a error? what is the problem actually?
Thank you in advance
my code is here under:
public static List<string> klantgegevens = new List<string>();
public static void Main(string[] args)
{
retry:
string naam;
int verzekeringkeuze;
string alleklantgegevens;
Console.WriteLine("wat is u naam");
naam = Console.ReadLine();
if (klantgegevens.Contains(naam))
{
Console.WriteLine("deze naam bestaat al");
}
else
{
Console.WriteLine("kies u soort verzekering: 1-auto,2-leven,3-woning");
verzekeringkeuze = int.Parse(Console.ReadLine());
switch (verzekeringkeuze)
{
case 1:
Console.WriteLine(alleklantgegevens = $"{naam}:auto");
break;
case 2:
Console.WriteLine(alleklantgegevens = $"{naam}:leven");
break;
case 3:
Console.WriteLine(alleklantgegevens = $"{naam}:woning");
break;
default:
break;
}
Console.WriteLine($"{naam} werd correct ingeschreven");
Console.ReadLine();
alleklantgegevens = $"{naam}:{verzekeringkeuze}";
klantgegevens.Add(alleklantgegevens);
}
Printall();
goto retry;
}
public static void Printall()
{
foreach (string gegevens in klantgegevens)
{
Console.WriteLine($"alle klantgegevens:{gegevens}");
}
Console.ReadLine();
}
No error because you check Contains(naam) not $"{naam}:{verzekeringkeuze}" which is what you put in the list.

How to keep prompting for input until it is valid?

I'm trying to make it so when the given answer is neither 1 nor 2 the message "Please enter a valid answer." shows up and it goes back to the question.
Here's my code:
Coloration(ConsoleColor.DarkMagenta, "What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int i = 0;
string input1 = Console.ReadLine();
// If answer is not 2, go through this, if answer is 2 continue
if (input1 != "2")
{
// If answer is 1 add 1 to i
if (input1 == "1")
{
i++;
}
// If answer is neither 1 nor 2; go back to question
if (input1 != "1" || input1 != "2")
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
}
}
You want something more like this...
Console.WriteLine("What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int userChoice = 0;
bool validInput = false;
while (!validInput)
{
Console.WriteLine();
Console.WriteLine("Enter choice [1/2]...");
string input = Console.ReadLine();
string trimmedInput = input.Trim();
if (trimmedInput == "1" || trimmedInput == "2")
{
validInput = true;
userChoice = Int32.Parse(trimmedInput);
}
}
// We leave the while loop here once validInput == true
// Now take action based on userChoice
Console.WriteLine("You chose " + userChoice);
Console.ReadLine();
As others have noted, you need to keep watching user input. You have your answer but I wanted to also introduce you to the concept of a Read Eval Print Loop (AKA a REPL). Your current solution is not going to scale well. Take a look at the following implementation of your desired UI:
using System;
using System.Collections.Generic;
namespace MyProgram
{
class Program
{
// Don't actually use inner classes. This is just for demonstration purposes.
class Command
{
public Command(string description, Action action)
{
this.Description = description;
this.Action = action;
}
public string Description { get; private set; }
public Action Action { get; private set; }
}
static void Main(string[] args)
{
// Create a dictionary of commands, mapped to the input that evokes each command.
var availableCommands = new Dictionary<string, Command>();
// Note that since we are storing the descriptions / commands in one place, it makes
// changing a description or adding/modifying a command trivial. Want "Draw" to be invoked
// by "d" instead of "1"? Change it here and you're done.
availableCommands.Add("1", new Command("Draw", Draw));
availableCommands.Add("2", new Command("Stay", Stay));
// This command demonstrates how to use a lambda as an action if you so desire.
availableCommands.Add("3", new Command("Exit", () => System.Environment.Exit(1)));
// Build command list string
var cmdList = string.Join('/', availableCommands.Keys);
// Display welcome message
Coloration(ConsoleColor.DarkMagenta, $"What do you want to do? [{cmdList}]");
// Show user initial list of commands
DisplayAvailableCommands(availableCommands);
// Read Eval Print Loop (REPL).
while (true)
{
var userInput = Console.ReadLine();
// If the user entered a valid command, execute it.
if (availableCommands.ContainsKey(userInput))
{
availableCommands[userInput].Action();
// If you want the user to be able to perform additional actions after their initial successful
// action, don't return here.
return;
}
// Otherwise, let them know they didn't enter a valid command and show them a list of commands
else
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
DisplayAvailableCommands(availableCommands);
}
}
}
// I'm just assuming your coloration method looks something like this...
static void Coloration(ConsoleColor color, string message)
{
// Keep track of original color so we can set it again.
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = originalColor;
}
static void DisplayAvailableCommands(Dictionary<string, Command> commands)
{
// We always want a line above the commands
Console.WriteLine("Available commands:");
foreach (string key in commands.Keys)
{
var command = commands[key];
Console.WriteLine($"{key}. {command.Description}");
}
}
static void Draw()
{
Coloration(ConsoleColor.DarkGreen, "You chose to draw!");
}
static void Stay()
{
Coloration(ConsoleColor.DarkGreen, "You chose to stay!");
}
}
}
Adding new commands will be a breeze. And you can further refactor this to even smaller single-purpose methods. Each command could have its' own class in the event that your commands become more complicated (and in a real app, they will. Trust me). You can refactor the REPL to its' own class/method as well (take a look at this implementation I did a while back for example).
Anyway, this is my $.02 on a more correct way you could build a user interface of this nature. Your current solution is going to work, but it's not going to be fun to work with long-term. Hopefully this helps.
use a while loop to continuously ask for input if not valid, then check the input with a switch statement
bool flag = false;
while(!flag)
{
switch(input1)
{
case "1":
flag = true;
break;
case "2":
flag = true;
break;
default:
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
break;
}
}

How to add an instantiated object to list and print the list to the console

Working on an assignment and need a little help. I'm trying to have the user input their list of fun places to visit and as they add the places I want to save it to a list and then give them the option to view the entire list of places. I'm having trouble saving the objects to a list:
using System;
using static System.Console;
namespace Assignment_4
{
class Program
{
static void Main()
{
Test.DisplayInstructions();
Test.AddPlace();
WriteLine("Would you like to add another place, Y/N?");
var addAnother = ReadKey().KeyChar;;
switch (char.ToLower(addAnother))
{
case 'y':
Test.AddPlace();
break;
case 'n':
break;
default:
break;
}
WriteLine("Would you like to see your list of fun places? Y/N");
var reviewList = ReadKey().KeyChar;
switch (char.ToLower(reviewList))
{
case 'y':
WriteLine(Test.funPlacesList);
break;
case 'n':
break;
default:
break;
}
}
}
}
This is the test I run to check the program:
using System;
using System.Collections.Generic;
using static System.Console;
namespace Assignment_4
{
public class Test
{
internal static void DisplayInstructions()
{
WriteLine("Welcome to my application: \n This app will you write about your favorite places \n" +
"To begin we'll need you to provide the information as prompted \n" +
"The app will then take that info and display it back to you. Showing you your favorite place!");
}
public static List<FunPlace> funPlacesList = new List<FunPlace>();
internal static void AddPlace()
{
FunPlace place = new FunPlace();
WriteLine("What is the name of this place?");
place.PlaceName = ReadLine();
WriteLine("Where is it located?");
place.PlaceAddress = ReadLine();
WriteLine("What kinds of fun things can you do there?");
place.PlaceDescription = ReadLine();
WriteLine("Any additional Comments to add?");
place.PlaceComments = ReadLine();
WriteLine("Provide a rating from 0.0 - 5.0.");
place.PlaceRating = float.Parse(ReadLine());
funPlacesList.Add(place);
ReadKey();
}
}
}
It looks to me like you're adding to the list just fine. You can't just Console.WriteLine(funPlacesList) though, all you're going to get is the name of the class. You need to loop over the collection and write out each entry individually.
foreach(var funPlace in Test.funPlacesList)
{
WriteLine(funPlace.PlaceName);
WriteLine(funPlace.PlaceAddress);
// etc...
}
foreach (FunPlace place in Test.funPlacesList)
{
Console.Writeline(place.PlaceName);
}
Is this what you were looking for? foreach can be used to loop through a collection of objects(list, array etc.) and reference each one inside the foreach block as place in this example.
For the record, I highly recommend coming up with another name for your Test class. Good names are a crucial long-term investment in the ease of understanding your code.

How to get values from one class use in another?

I am really new to this, but I have 3 classes, and one of them uses the command line to ask the user to press 1 or 2 to answer questions, and then I am using a get; set; to collect that information in a different class.
I want to write that information into a text document. The problem is, my class where I am using StreamWriter isn't recognizing the words I used to define the information in the other class. Any help would be great. This is where I want the information to go.
StreamWriter writer = new StreamWriter(#"C:\Users\Dan\Documents\testText.txt");
writer.WriteLine("Passenger Information" //want the SeatSelection in here);
writer.Close();
The original information comes from here. Although in this code, it is recognizing the word "SeatSelection"? Why is it recognizing here but not above?
Console.Clear();
Console.WriteLine("Please select first or third class for your trip. ");
Console.WriteLine("1) First Class Compartment.");
Console.WriteLine("2) Third Class with Compartments.");
Console.WriteLine("3) Car C Open seating.");
Console.WriteLine("4) Car D Open seating.");
Console.WriteLine("5) Return to booking main menu.");
bool validInput = false;
do
{
validInput = true;
ConsoleKeyInfo key = Console.ReadKey();
switch (key.Key)
{
case ConsoleKey.D1:
case ConsoleKey.NumPad1:
seatClass.SeatSelection = "First Class";
FirstClass();
break;
case ConsoleKey.D2:
case ConsoleKey.NumPad2:
seatClass.SeatSelection = "Third Class Compartment";
ThirdClassCompartments();
break;
I'm not sure what your application structure is, but you want something along these lines:
var seatClass = UserInterface.GetSeatClass();
StreamWriter writer = new StreamWriter(#"C:\Users\Dan\Documents\testText.txt");
writer.WriteLine("Passenger Information" + seatClass.SeatSelection);
writer.Close();
...where the I have creatively inserted an imaginery UserInterface static class that returns a new instance of a SeatClass from it's GetSeatClass method:
public static class UserInterface
{
public static SeatClass GetSeatClass()
{
var seatClass = new SeatClass();
//code here that assigns values to seatClass
return seatClass;
}
}
I can give you a better answer with more information. Please don't hesitate to ask any questions. (I'm sorry I've used a static class when you're just starting out. I can explain if required.)
You can use this
var filePath = #"C:\Users\Dan\Documents\testText.txt";
var lines = new[] {"a line content"};
System.IO.File.AppendAllLines(filePath, lines);
Instead of StreamWriter stuff.

Categories

Resources