Calling function in yet uninstanced object C# - c#

I'm trying to create menu for my simple app. I want to use switch but I can't find a way to call functions in uninstanced class which is instanced on application startup.
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
this.mainMenu();
}
public void mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
break;
How do I call MainLibrary's function in case 1. It's obviously not instanced here but I can't find a way pass reference to uninstanced object.
BookList code :
class BookList
{
List<Book> books = new List<Book>();
public void addBook() // adding book
{
string name = Console.ReadLine();
string author = Console.ReadLine();
int relDate = int.Parse(Console.ReadLine());
int uID = books.Count() + 1;
books.Add(new Book(name, author, relDate, uID));
}
public void deleteBook() // deleting book
{
int readForDelete = int.Parse(Console.ReadLine());
books.RemoveAll(Book => Book.UniqueID == readForDelete);
}
public void borrowBook() // borrowing book
{
int readForBorrow = int.Parse(Console.ReadLine());
foreach (Book Book in books)
{
if (Book.UniqueID == readForBorrow)
Book.available = false;
}
}
public void returnBook() // returning book
{
int readForReturn = int.Parse(Console.ReadLine());
foreach (Book Book in books)
{
if (Book.UniqueID == readForReturn)
Book.available = true;
}
}
public void displayBooks() // displaying list of books
{
string isAvailable;
foreach (Book Book in books)
{
if (Book.available == true)
isAvailable = "available";
else
isAvailable = "unavailable";
Console.WriteLine(" {0} {1} {2} {3} {4} ", Book.UniqueID, Book.BookName, Book.BookName, Book.ReleaseDate, isAvailable);
}
}
public string Name
{
get; set;
}
}
}

You either need to pass your BookList instance to your mainMenu() method, or set a global variable. I'd recommend the former.
public void mainMenu(BookList list) { ... }
Then call it like this from startLibrary:
this.mainMenu(MainLibrary);
As a side note, you really need to brush up on your variable, class, and method naming conventions.

You could implement it with lambdas like this:
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
Action<BookList> action = this.mainMenu();
if (action != null)
{
action(MainLibrary);
}
}
public Action<BookList> mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
return b => b.addBook();
}
Or you could just pass a reference to your MainLibrary variable to the method:
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
this.mainMenu(MainLibrary);
}
public Action<BookList> mainMenu(BookList b)
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
b.addBook();
break;
}

First of all, what you've got in your startLibrary method is a local variable - which is accessible only within the block it's defined in. That said, the MainLibrary is not something you can reference from anywhere else.
To solve your problem you have several options.
You can make the MainLibrary a field/member of the Window class. Then all the instance methods of the Window class will have access to it - so as the MainMenu method:
class Window
{
private BookList MainLibrary;
public void startLibrary(int sizeX, int sizeY)
{
this.MainLibrary = new BookList();
this.mainMenu();
}
public void mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
// do whatever you want with this.MainLibrary here
break;
/// ...
}
}
}
The other option would be to pass in the MainLIbrary instance you've created into the mainMenu method. Here you'll need to update the signature of the method as follows:
public void mainMenu(BookList list)
{
// reference the list now as necessary
}

Related

Crash when class write to console

I'm going to get another user and enter which month he wants and find the quarter.
Thought of writing the code inside a class as I need more training on how to use classes.
The program asks whose month it is and I can enter. But now when I type "January" only programs crash.
I assume that it should show which quarter "january" is in
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Write a month");
var mc = new MyClass();
mc.month = Convert.ToString(Console.ReadLine());
}
public class MyClass
{
public string month;
public string Prop
{
get
{
return month;
}
set
{ if (Prop == "january")
{
Console.WriteLine("1.quarter");
}
}
}
}
}
}
Consider presenting a menu which in the case below uses a NuGet package Spectre.Console and docs. This gives you an opportunity to work with classes and ensures, in this case input is a valid month along with reties and how to exit.
First a class for the menu.
public class MonthItem
{
public int Index { get; }
public string Name { get; }
public MonthItem(int index, string name)
{
Index = index;
Name = name;
}
public override string ToString() => Name;
}
Class which creates the menu
class MenuOperations
{
public static SelectionPrompt<MonthItem> SelectionPrompt()
{
var menuItemList = Enumerable.Range(1, 12).Select((index) =>
new MonthItem(index, DateTimeFormatInfo.CurrentInfo.GetMonthName(index)))
.ToList();
menuItemList.Add(new MonthItem(-1, "Exit"));
SelectionPrompt<MonthItem> menu = new()
{
HighlightStyle = new Style(Color.Black, Color.White, Decoration.None)
};
menu.Title("[yellow]Select a month[/]");
menu.PageSize = 14;
menu.AddChoices(menuItemList);
return menu;
}
}
Present menu, get selection and show details or exit.
static void Main(string[] args)
{
while (true)
{
Console.Clear();
var menuItem = AnsiConsole.Prompt(MenuOperations.SelectionPrompt());
if (menuItem.Index != -1)
{
AnsiConsole.MarkupLine($"[b]{menuItem.Name}[/] index is [b]{menuItem.Index}[/]");
Console.ReadLine();
}
else
{
return;
}
}
}
I tested your code and your program is not crashing. The program is actually completing and therefore the console is closing due to execution completing. So you can see what I mean try changing your code to this. You will see your code loop and the console will not close. It will also display what the user types in for mc.month
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("Write a month");
var mc = new MyClass();
mc.month = Convert.ToString(Console.ReadLine());
Console.WriteLine(mc.month);
}
}
On a side note, not really how I would use a class. You might want to also rethink that. Don't normally see writelines in class.

How to pass value in ArrayList from method to method

public Program()
{
amount_bike = new ArrayList();
}
public void push(int value)
{
this.amount_bike.Add(value);
}
public int amount_bike_pop()
{
if (this.amount_bike.Count == 0)
{
return -100000;
}
int lastItem = (int)this.amount_bike[this.amount_bike.Count - 1];
this.amount_bike.RemoveAt(this.amount_bike.Count - 1);
return lastItem;
}
public static void Bike_status()
{
bool exit = false;
Program available = new Program();
available.push(0);
available.push(0);
available.push(50);
WriteLine("E-bike available for rent is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Rented E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Broke E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("\n");
WriteLine("Please enter a number: 1 is back to pervoius menu or 0 to Exit");
int input = Convert.ToInt32(ReadLine());
while (exit == false)
{
if (input == 1)
{
Clear();
exit = true;
continue;
}
else if (input == 0)
{
Clear();
Exit();
}
else
{
Clear();
Bike_status();
}
}
}
public static void Add_bike()
{
}
I study data structures and Algorithms. In this code, I keep the value in an ArrayList named "available" in the Bike_status method. I need to pass a value in an ArrayList to the Add_bike method. How do I pass a value from one method to another? Actually, I need to pass valus such as 50 to plus some number that I push in Console.ReadLine.
Try to slow down.at starting point of programming sometimes it's confusing.
How do I pass a value from one method to another?
The simple answer is easy ,you want something to use in the function then in your method(s) you create parameter and pass the things you want to it.
like
//edit method to get int value -> public static void Bike_status()
public static void Bike_status(int value)
//edit when to call
else
{
Clear();
Bike_status(input);//send int value in
}
But really, what is that do you really want to learn?
if it OOP? I recommend you study this
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/
To put it simply you has bicycle shop class separate from main program then use the method in that class
e.g.
//bicycle class
public class Bicycles{
public int ID {get;set;}
pulibc string status {get;set; }
public Bicycles(int p_id, string p_status)
{
ID = p_id;
status=p_status;
}
}
//bicycle shop class
public class BicyclesShop{
public List<Bicycle> available {get;set;} // class member
public BicyclesShop() // go search keyword "constructor"
{
available = new List<Bicycle> ();
}
//other method
public void Add_bike()
{
// I can access available object !
// do anything with this class member(s) !
}
public void Bike_status(int inputVal)
{
// do something with inputVal , change some properties?
}
//other methods
public int amount_bike_pop()
{
return available.Count();
}
public int amount_bike_broken_pop()
{
return available.Where(o=>o.status =="Broken").Count(); // go search linq
}
}
//To use in Main program method
BicyclesShop bs =new BicyclesShop();
bs.available.Add( new Bicycle(1 ,"OK") ); //add bicycle #1 in list
bs.available.Add( new Bicycle(2),"Broken" ); //add bicycle #2 in list
WriteLine("Broke E-bike is : " + bs.amount_bike_broken_pop() + " bikes.");

using a class method beside a while loop in c#

I am trying to use a while loop when using a public static class method.
I don't know where to break the loops (while and foreach).
the target is, prompting the user to enter a correct format of his name which contains all letters.
namespace Project1
{
public class Student
{
public int id;
public string name;
public string familyName;
public int age;
public static int numberOfStudents;
public static void IsAllLetter(string name)
{
while (true)
{
foreach (char c in name)
{
if (!char.IsLetter(c) || name == null)
{
break;
}
}
Console.WriteLine("name and family name must contain letters");
Console.WriteLine("please try again");
}
}
}
public class Program
{
public static void Main(string[] args)
{
// get the name
Student student1 = new Student();
Console.WriteLine("name of the student?");
student1.name = Console.ReadLine();
Student.IsAllLetter(student1.name);
}
}
}
Let's extract method, name validation:
using System.Linq;
...
// Simplest, some names like
// "Charles de Batz de Castelmore d'Artagnan"
// does not pass
private static bool IsValidName(string value) {
return
!string.IsNullOrEmpty(value) && // value can't be null or ""
value.All(letter => char.IsLetter(letter)); // All letters validation
}
Then we can implement a name input:
private static string ReadName(string title) {
while (true) {
if (!string.IsNullOrEmpty(title))
Console.WriteLine(title);
// .Trim() - let be nice and tolerate leading / trailing whitespaces
string name = Console.ReadLine().Trim();
if (IsValidName(name))
return name;
Console.WriteLine("Sorry, the name is not valid. Please, try again");
}
}
Finally, you can just use these methods in your business logic without delving into validation details:
Student student1 = new Student();
student1.name = ReadName("name of the student?");
You need only a single loop that iterates the characters in your string and return false if any "wrong" character was found:
public static bool IsAllLetter(string name)
{
if(string.IsNullOrEmpty(name))
return false;
foreach (char c in name)
{
if (!char.IsLetter(c) || name == null)
{
return false;
}
}
return true;
}
Than call that method in a loop:
string name;
while(true)
{
Console.WriteLine("name of the student?");
name = Console.ReadLine();
if(IsAllLetter(name) break;
}
Now you have a name which you can assign to your Student:
var s = new Student { Name = name };

Processing int to name of list

I try to write a simple console application with Hanoi towers. But I am stuck at one point.
In my program I ask a person to write from to which tower wants to put the disk, but: I have 3 lists as towers, I'll ask for a number from gamer and now how I can build a "compare method"? Because I don't want to copy the same piece of code 6 times...
class Towers : Disks
{
//public Towers(int Value, int WhereItIs) : base(Value, WhereItIs) { }
public List<Disks> Tower1 = new List<Disks>();
public List<Disks> Tower2 = new List<Disks>();
public List<Disks> Tower3 = new List<Disks>();
public void Compare(int dyskFrom, int dyskWhere) {
}
public void Display() {
foreach(var i in Tower1){
Console.WriteLine("Where: {0} | Value: {1}", i.WhereItIs, i.Value);
}
}
public void Build(int TowerHigh) {
for (int i = TowerHigh; i > 0; i--) {
Tower1.Add(new Disks {Value = i, WhereItIs = 1 });
}
}
}
class Disks
{
public int Value; //wartosc krazka
public int WhereItIs; //na ktorej wiezy sie on znajduje
}
class Program
{
static void Main(string[] args)
{
Towers Tower = new Towers();
int TowerHigh;
Console.Write("Podaj wysokość wieży: ");
TowerHigh = int.Parse(Console.ReadLine());
Tower.Build(TowerHigh);
Tower.Display();
Tower.Compare(1, 2);
}
}
It's easier to create an array of Stack<Disk>(). This way you can select a tower by index.
I would use a Stack, because thats typically the functionality you need.
Something like: PSEUDO (typed in browser, no syntax checked)
class Disk
{
public int Size {get; set;}
}
static void Main(string[] args)
{
// create the Stack<Disk> array
Stack<Disk>[] towers = new Stack<Disk>[3];
// create each tower
for(int i=0;i<towers.Length;i++)
{
towers[i] = new Stack<Disk>();
// fill the towers.
for(int j=3;j>0;j--)
towers[i].Enqueue(new Disk { Size = j });
}
bool isHoldingDisk = false;
while(true)
{
DisplayTowers(towers);
if(isHoldingDisk)
Console.WriteLine("On what tower do you want to place it?");
else
Console.WriteLine("Choose a tower to pick a disk");
var key = Console.ReadKey(true);
var chosenTowerIndex = 0;
switch(key)
{
case(Key.Escape):
break;
case(Key.D1):
chosenTowerIndex = 0;
break;
case(Key.D1):
chosenTowerIndex = 1;
break;
case(Key.D1):
chosenTowerIndex = 2;
break;
// etc...
}
if((chosenTowerIndex < 1) || (chosenTowerIndex >= towers.Length))
continue;
// check here if you are holding a disk
if(isHoldingDisk)
{
// logic for testing if you can place the disk here...
// using towers[chosenTowerIndex]
// check if it is completed...
if(completed)
break;
isHoldingDisk = false;
}
else
{
// check if you can pickup a disk....(if there is any)
isHoldingDisk = true;
}
}
// final display...
DisplayTowers(towers);
Console.WriteLine("Thanks for playing");
}
static void DisplayTowers(Stack<Disk>[] towers)
{
// draw some fancy asc-ii art...
}

I need a simple and elegant user validation technique for a c# console application

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;
}
}

Categories