Editing users info with struct - c#

struct person
{
public int id;
public long phone;
public string name, family, add;
public void Show()
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", id, name, family, phone, add);
}
}
class Program
{
static List<person> info = new List<person>();
static void Edit()
{
Display();
Console.Write("Choose your target ID:");
int ed = Convert.ToInt32(Console.ReadLine());
for (int i = 0; i < info.Count; i++)
{
if (ed == info[i].id)
{
Console.WriteLine("1.ID\n2.Name\n3.FamilyName\n4.PhoneNumber\n5.Address\n6.Exit to menu");
Console.WriteLine("Which part of the user info would you like to update:");
int ed1 = Convert.ToInt32(Console.ReadLine());
bool exm = false;
while (true)
{
switch (ed1)
{
case 1:
break;
case 2:
Console.Write("Enter Your Name:");
info[i].name = Console.ReadLine();
break;
case 3:
Console.Write("Enter Your FamilyName:");
info[i].family = Console.ReadLine();
break;
case 4:
Console.Write("Enter Your Name:");
info[i].phone = Convert.ToInt64(Console.ReadLine());
break;
case 5:
Console.Write("Enter Your Name:");
info[i].add =Console.ReadLine();
break;
case 6:
if (exm == true)
Main();
break;
default:
Console.WriteLine("Invalid Operation");
break;
}
}
}
}
}
I'm trying to make a program that gets users info then shows them what they can do. The program methods include input, display, search, remove, edit, all work fine but edit. I don't know how to make it work.
For edit I'm gonna get user id, then let him choose which part of that id he wants to change. In all cases I tried to replace new info but it shows me an error on info[i].would you help me to do this in this way?

You cannot change a property of a struct stored in a list; either change your struct to a class and you will then be able to modify individual properties, or change your editing routine so that it either
creates a whole new Person struct using all the data from the existing person struct with the new bit of data you want to change, and replace the old person struct in the list with the new one you've made or
gets the person out of the list into a temporary variable, changes the name, puts the temp variable back into the list
As an academic exercise I suppose it's teaching you about value types but it's a bit abstruse; perhaps your teacher is hoping you will pick up on the fact that accessing list[x] creates a copy of what is in the list at x. As there is no point editing a copy (and then throwing the copy away, as a direct edit would do) the compiler warns you that it's not possible.

You are getting the error because structs are value type.
When you do info[i] it returns value of the element at i rather than the reference to it. Modifying this value by calling setter doesn't change anything in the actual struct instance. Hence the error.
A naive workaround would be
info[i]=new person{name= Console.ReadLine()};
If not for an assignment, you should definetely use classes in these cases

Related

Instantiating User Defined Object inside Another Object in C#

I need some help with the way I am storing objects/data inside my application. I am creating an application that: creates a robot, assigns tasks to robot, displays the robot information with task time etc..
I have setup multiple different objects to be instantiated in Main when the program is run. Then the user will select a robot type from the list of types. I am having trouble passing the botType object into the Robot object. I am asking the user to select a botType 1-6 using int, then I would like the user selected int to define which botType should be applied to the Robot.
Because I am initializing the BotTypes in Main, then using a different method to CreateRobot(). I am having trouble passing the botType into the Robot object. I can pass the integer the user selects but this is not passing the botType into Robot like I am trying to complete..
Here are my classes/constructors being used:
public class Robot
{
//Store robot name
public string botName { get; set; }
//Store robot type
public BotType botType { get; set; }
//Store time to complete task
public int timeElapsed { get; set; }
public Robot(string BotName, BotType botType, int TimeElapsed)
{
this.botName = BotName;
this.botType = new BotType();
timeElapsed = TimeElapsed;
}
public class BotType
{
//Type of robot
public string TypeName { get; set; }
//Type of task represented by number
public int TaskType { get; set; }
//contructor to set values
public BotType (string typeName, int taskType)
{
TypeName = typeName;
TaskType = taskType;
}
Then my main method where the objects are being initialized but when I try to use them, I am unable to convert user defined int into BotType like I would like..
public class BotOMat
{
public static List<Robot> botList = new List<Robot>();
public static List<BotTask> botTaskMap = new List<BotTask>();
public static List<BotType> botTypeMap = new List<BotType>();
static void Main(string[] args)
{
//initalize bot types
BotType UNIPEDAL = new BotType("Unipedal", 1);
BotType BIPEDAL = new BotType("Bipedal", 2);
BotType QUADRUPEDAL = new BotType("Quadrupedal", 3);
BotType ARACHNID = new BotType("Arachnid", 4);
BotType RADIAL = new BotType("Radial", 5);
BotType AERONAUTICAL = new BotType("Aeronautical", 6);
//initialize bot tasks
BotTask DISHES = new BotTask("Do the dishes", 1000, 0);
BotTask SWEEP = new BotTask("Sweep the house", 3000, 0);
BotTask LAUNDRY = new BotTask("Do the laundry", 10000, 0);
BotTask RECYCLING = new BotTask("Take out the recycling", 4000, 0);
BotTask SAMMICH = new BotTask("Make a sammich", 7000, 0);
BotTask LAWN = new BotTask("Mow the lawn", 20000, 0);
BotTask RAKE = new BotTask("Rake the leaves", 18000, 0);
BotTask BATH = new BotTask("Give the dog a bath", 14500, 0);
BotTask BAKE = new BotTask("Bake some cookies", 8000, 0);
BotTask WASH = new BotTask("Wash the car", 20000, 0);
var botTaskMap = new List<BotTask> { DISHES, SWEEP, LAUNDRY, RECYCLING, SAMMICH, LAWN, RAKE, BATH, BAKE, WASH };
var botTypeMap = new List<BotType> { UNIPEDAL, BIPEDAL, QUADRUPEDAL, ARACHNID, RADIAL, AERONAUTICAL };
private static void createRobot()
{
//Get robot name, add to list saving multiple names.
Console.WriteLine("Enter robot name:");
string botName = Console.ReadLine();
//Get robot type
Console.WriteLine("Enter robot type: (number)");
int botType = Convert.ToInt32(Console.ReadLine());
//botType = botTypeMap[botType];
//boxing to convert int to BotType
//error handling
if (botType < 1 || botType > 6)
{
Console.WriteLine("Invalid input. Please enter number 1-6.");
//BotType.TaskType = 0;
}
//Add robot to the class storing robot information.
if (botType > 1 || botType < 6)
{
Robot aRobot = new Robot(botName, botType, 0);
botList.Add(aRobot);
aRobot.AssignBotTask();
aRobot.CompleteTask();
}
else
{
MainMenu();
}
}
I can either pass BotType into Robot as an Integer or receive an Arguement 2: cannot convert from int to BotOMat.BotType. Whenever I try to write any output using aRobot the console is writing using the protected variables which is not the desired output.
Should I be creating aRobot in the Robot class? I then need to assign BotTask(s) to the robot later on... I believe these use an Association type relationship but if the objects are not initialized in each class. I am unsure how to initiate; for example: a Unipedal Robot that does the Dishes.
I appreciate any help in advance. I tried to be as descriptive as possible without posting a repeat question as any other example I can find is much more basic than what I believe I am trying to accomplish here.
The next time you post a question, you should take a look at the help, particularly in regards to preparing a Minimally Reproduceable Example. Your code doesn't compile, you are missing types, functions, etc. Some of what I'm going to show below doesn't quite comport to what you show, but it certainly seems to meet your intention (at least to me).
I'm going to start at the bottom layer and work up. Your BotType class simply has a string and an int (with the ints incrementing). Instead of using a class, I'm going to use an enum (you should read up on these). Enums are value types. Under the covers, they end up being represented by a simple integral-valued type (like int), but with the metadata they include, they have a symbolic name as well. So:
public enum RobotType
{
Unipedal = 1,
Bipedal,
Quadrupedal,
Arachnid,
Radial,
Aeronautical,
}
Had I not included the =1, then Unipedal would have started with the default value (zero). You'll see why starting at one makes sense below. The nice thing about enums is that you can convert them to an integer, or to a string that represents their symbol. You can also parse either a string containing an integer or a string containing symbolic name to an enum instance:
var asInt = (int) RobotType.Unipedal;
var asString = RobotType.Unipedal.ToString();
bool isGoodParse = Enum.TryParse<RobotType>("1", out RobotType parsedFromInt);
isGoodParse = Enum.TryParse<RobotType>("Unipedal", out RobotType parsedFromString);
All that code works the way you might expect.
It's tempting to just do the same thing with your task types. But the names aren't valid C# symbols (they have spaces). Instead, we'll use System.ComponentModel.DescriptionAttribute to add some extra metadata to the enum values:
public enum RobotTaskName
{
[Description("Do the dishes")]
DoTheDishes = 1,
[Description("Sweep the house")]
SweepTheHouse,
[Description("Do the laundry")]
DoTheLaundry,
[Description("Take out the recycling")]
TakeOutTheRecycling,
[Description("Make a sammich")]
MakeASammich,
[Description("Mow the lawn")]
MowTheLawn,
[Description("Rake the leaves")]
RakeTheLeaves,
[Description("Give the dog a bath")]
GiveTheDogABath,
[Description("Bake some cookies")]
BakeSomeCookies,
[Description("Wash the car")]
WashTheCar,
}
But, now we can't just call ToString on the enum value to get the corresponding name. Instead, we'll use reflection to dig the name out of the Description attribute:
public static class RobotExtensions
{
public static string GetDescription<T>(this T enumValue) where T : struct, Enum
{
var enumInfo = typeof(T).GetField(enumValue.ToString());
if (enumInfo != null)
{
var attributes = enumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
return ((DescriptionAttribute[])attributes)[0].Description;
}
}
//otherwise
return enumValue.ToString();
}
}
That code declares an Extension Method for enums (you can call it directly on an enum - any enum). It gets reflected Field Information for the enum value, checks to see if it has an DescriptionAttribute. If it does, it digs out the description and returns it. If it can't get that information, it simply returns enumValue.ToString. As a result:
RobotTaskName.DoTheDishes.GetDescription(); //returns "Do the dishes"
RobotType.Arachnid.GetDescription(); //returns "Arachnid"
The other cool thing about doing it this way, is that we can write some code that prompts the user for a particular enum value, checks it's validity, etc:
public static T? GetResponseUsingEnum<T>(string prompt) where T : struct, Enum
{
//Loop until a good answer (or no answer)
while (true)
{
Console.WriteLine($"{prompt}: Please enter one of:");
var values = (T[])Enum.GetValues(typeof(T));
foreach (var enumValue in values)
{
var description = enumValue.GetDescription<T>();
var intValue = Convert.ToInt32(enumValue);
Console.WriteLine($"{intValue}: {description}");
}
Console.Write(">> ");
var response = Console.ReadLine();
if (string.IsNullOrEmpty(response))
{
return (T?)null;
}
if (Enum.TryParse<T>(response, out var val))
{
if (values.Contains(val))
{
Console.WriteLine($"You answered: {val}");
return val;
}
}
}
}
That code shows the integer and string representations of all of the values of a particular enumerated type, and then prompts the user to enter a value. If the user enters a value out of range, then it re-prompts him/her. If the user just hits Enter, then it returns a null value. Otherwise, if the user enters a valid answer, it returns the answer (not as an integer, but as a properly typed enumerated item.
Now that the bottom layer is complete, let's work up ...
I couldn't quite tell what your Robot Task type does, or what the extra two integers where, so I called them Num1 and Num2. I also added a Perform function that "performs" the task (echoes it to the console).
public class BotTask
{
public RobotTaskName Name { get; set; }
public string Description => Name.GetDescription();
public int Num1 { get; set; }
public int Num2 { get; set; }
public BotTask(RobotTaskName name, int num1, int num2)
{
Name = name;
Num1 = num1;
Num2 = num2;
}
public void Perform()
{
Console.WriteLine($" - Peforming Task: {Name.GetDescription()} with {Num1} and {Num2}");
}
}
If you are curious, the Description property is a read-only property that calls GetDescription on the underlying RobotTaskName enumerated type.
Then I recreated your Robot type. I don't know what your intention was for the TimeElapsed property. But, I changed it to a TimeSpan from an int - because, well, that's what TimeSpans are for.
public class Robot
{
public string BotName { get; set; }
public RobotType BotType { get; set; }
public string BotTypeDescription => BotType.GetDescription();
public TimeSpan TimeElapsed { get; set; }
private List<BotTask> _tasks = new List<BotTask>();
public IEnumerable<BotTask> Tasks => _tasks;
public Robot(string botName, RobotType botType, TimeSpan timeElapsed = default)
{
this.BotName = botName;
this.BotType = botType;
TimeElapsed = timeElapsed;
}
public void AddTask (BotTask task)
{
_tasks.Add(task);
}
public void Show()
{
Console.WriteLine($"Robot: {BotName}, Type: {BotTypeDescription}, TimeElapsed: {TimeElapsed}");
foreach (var task in Tasks)
{
task.Perform();
}
}
}
Note that I also added a list of tasks that have been assigned to each robot. That includes the list, an AddTask method to add tasks to a robot, etc.
Finally, I added a Run method to the Robot class that fires the whole thing off (call it from Main). It allows you to create more than one robot and to assign more than one task to each robot. It uses the GetResponseUsingEnum method to get both the robot type and the task type. This means a consistent user interface and some healthy code reuse (if you find a bug in that function, you fix two pieces of functionality).
public static void Run()
{
var robotsList = new List<Robot>();
//loop until there are no more robots
while (true)
{
Console.Write("Enter robot name: ");)
var robotName = Console.ReadLine();
if (string.IsNullOrEmpty(robotName))
{
break; //empty robot, time to list things out
}
RobotType? robotType = null;
while (!robotType.HasValue)
{
robotType = GetResponseUsingEnum<RobotType>("Robots");
}
var robot = new Robot(robotName, robotType.Value);
robotsList.Add(robot);
Console.WriteLine("Time to add some tasks for this robot");
//get tasks - loop until no more tasks
while (true)
{
var taskName = GetResponseUsingEnum<RobotTaskName>("RobotTaskName");
if (!taskName.HasValue)
{
break; //no more tasks
}
var task = new BotTask(taskName.Value, 100, 200);
robot.AddTask(task);
}
}
//At this point, we have a fully populated list of robots, each with some tasks
foreach (var robot in robotsList)
{
robot.Show();
}
}
Finally, if you run it, the output looks like this:
Enter robot name: Robby
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 2
You answered: Bipedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 2
You answered: SweepTheHouse
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 3
You answered: DoTheLaundry
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name: SecondRobot
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 3
You answered: Quadrupedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 8
You answered: GiveTheDogABath
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 10
You answered: WashTheCar
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name:
Robot: Robby, Type: Bipedal, TimeElapsed: 00:00:00
- Peforming Task: Sweep the house with 100 and 200
- Peforming Task: Do the laundry with 100 and 200
Robot: SecondRobot, Type: Quadrupedal, TimeElapsed: 00:00:00
- Peforming Task: Give the dog a bath with 100 and 200
- Peforming Task: Wash the car with 100 and 200

alternative to global variable for running total

I am very much a novice with C#, but for class I must write a program which keeps a running total of food sales.
We have been taught to use global variables, but not only does it not feel like the easiest way, everywhere I read says not to use them.
Without using a global variable, I have not found a way to keep the cost of two different chocolate bars, for example. It works to get the total cost of 1 bar - regardless of quantity, but when I add another, any previous selections disappear from the total cost.
So in short: what I have works, but I feel that I need to learn a better practice.
Here is a sample of my code (note that there is more than one method which I have not copied into here):
class Program
{
static double total = 0;
static void Main(string[] args)
{
string choice = "y";
while (choice == "y")
{
Console.WriteLine("Main Menu:\nChocolate\nSandwiches");
int menu = int.Parse(Console.ReadLine());
switch (menu)
{
case 1:
chocolate();
break;
case 2:
sandwich();
break;
}
}
}
static void chocolate()
{
int menu = 0;
//double cost = quant * price;
Console.WriteLine("Chocolate bar menu:\nMars bar\nSnickers\nTwix\nMilky Bar\nTurkish Delight");
int chocBar = int.Parse(Console.ReadLine());
Console.Clear();
Console.WriteLine("Quantity");
double quant = double.Parse(Console.ReadLine());
Console.Clear();
if (chocBar == 1)
{
Console.Clear();
double costMars = quant * 0.5;
total = total + costMars;
Console.WriteLine("current total: £" + total.ToString("0.00"));
Console.WriteLine("Press 1 for main menu");
menu = int.Parse(Console.ReadLine());
if (menu == 1)
{
chocolate();
}
else
{
}
}
if (chocBar == 2)
{
double costSnick = quant * 0.8;
total = total + costSnick;
Console.WriteLine("current total: £" + total.ToString("0.00"));
Console.WriteLine("Press 1 for main menu");
menu = int.Parse(Console.ReadLine());
if (menu == 1)
{
chocolate();
}
else
{
}
}
Console.ReadKey();
Congratulations for picking C# as a programming language to learn. It really is a great programming language.
What you read is correct, globals variables have many implications. It is usually last resort. Since you are a beginner I will recommend another simple technique. I found a great link for you that will introduce concepts of passing variables by value and reference. Check it out
https://msdn.microsoft.com/en-us/library/0f66670z.aspx
Good luck.
Good on you for being proactive about learning good coding practices early on in your education! I think your instructor is probably telling you to use globals for right now so as not to overload you with too many concepts at once, but yeah, as a general rule of thumb, you should try to pass variables around your code as method parameters instead. The reason is because if you have a global variable in a large application with tens of thousands of lines of code, and that global variable somehow ends up with an incorrect value in it, then it can be a real nightmare to figure out which piece of code wrote the incorrect value into the variable.
There are a variety of ways to allow data to flow into and out of methods when calling them. The worst way is to use a "global" variable.
Aside: C# technically does not have "global" variables per se, as the term describes variables that are fully accessible from any context, without qualification. All C# variables must be scoped to a type or a method. But, the same general caveats do apply to these kinds of variables. In C#, it is the usage that distinguishes whether a variable is declared along best practices or not, not the declaration itself.
In your code, the most obvious way to approach this would be to have each method return the value to be added to the total.
Also, for some reason, you have implemented your loop as a recursive call. It's not clear to me why you did that, but unless that's a specific requirement in your classroom assignment, I would recommend against it. You're unlikely to run into any specific problems in this context, but it's highly irregular, making the code hard to understand, and giving at least a theoretical possibility of a stack overflow (in reality, you're unlikely to find a user patient enough to cause that to happen, but there's not an actual guarantee in the code that the recursion will eventually terminate).
I am usually hesitant to rewrite homework assignments, but in this case I think you've provided enough code, and advice will be clearer if presented as more code. You still have some work to do, to implement the sandwich() method and the other candy bars, and I've only addressed the immediate problem, not the other flaws in the code. So I don't feel like I'm just doing your school-work for you. :)
Here is the general idea of what I think the code should look like:
class Program
{
static void Main(string[] args)
{
double total = 0;
string choice = "y";
while (choice == "y")
{
Console.WriteLine("Main Menu:\nChocolate\nSandwiches");
int menu = int.Parse(Console.ReadLine());
switch (menu)
{
case 1:
total += chocolate();
break;
case 2:
total += sandwich();
break;
}
Console.WriteLine("current total: £" + total.ToString("0.00"));
Console.WriteLine("Press 1 for main menu");
menu = int.Parse(Console.ReadLine());
}
}
static double chocolate()
{
int menu = 0;
Console.WriteLine("Chocolate bar menu:\nMars bar\nSnickers\nTwix\nMilky Bar\nTurkish Delight");
int chocBar = int.Parse(Console.ReadLine());
Console.Clear();
Console.WriteLine("Quantity");
double quant = double.Parse(Console.ReadLine());
Console.Clear();
double cost;
switch (chocBar)
{
case 1: // Mars
cost = 0.5;
break;
case 2: // Snickers
cost = 0.8;
break;
default:
throw new Exception("Invalid user input");
}
Console.Clear();
return quant * cost;
}
}
Notes:
It's not clear to me what the point of the prompt for "Press 1 for main menu" is. What could the user do at that point except return to the main menu? Whatever your intent, it seems likely that you will do the same thing regardless of whether the user has picked the "Chocolate" or "Sandwiches" option, so I moved that prompt out to the main method.
When dealing with currency, the decimal type is a better choice than double, because human beings don't like the rounding error that occurs with base-2 arithmetic in the double type. Using the decimal type ensures that values entered as decimal remain represented exactly as decimal, eliminating that source of rounding error.
It's not clear to me whether you really intend for the user to be able to purchase a fraction of a candy bar or not. The type you parse the input as is double, which would allow the user to buy e.g. 1.25 candy bars. If that's what you intend, fine. But if not, consider changing the type of the quantity user input to int.
Your original code had no mechanism to break out of the top-level menu, i.e. set choice to something other than "y". I did nothing at all to address that. The same issue still exists in the code here.
"Turkish Delight" may describe a wide variety of candies, but I've never seen one that I'd characterize as a chocolate bar. You might want to reconsider the top-level menu item description, if you're going to sell those. :)

how do i use an array in a switch statement in c#?

So i am new to programming so im pretty confused about this. I created an array and tried to use it inside of a switch statement:
string[] General = new string[5];
{
General[0] = "help";
General[1] = "commands";
General[2] = "hello";
General[3] = "info";
General[4] = "quit";
}
switch(General)
{
case 0:
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
continue;
}
}
As far as i am aware there are no problems with this. However, when i run the code i am greeted with this error : "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type"
I am genuinely stuck with this and i cant find any answers on the internet so any help will be greatly appreciated. Thanks
It sounds like what you are looking for is an enum.
public enum General {
help = 0,
commands = 1,
hello = 2,
info = 3,
quit = 4
}
Then you can use a switch statement just fine :).
// variable to switch
General myGeneral;
// myGeneral is set to something
switch(myGeneral)
{
case General.help:
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
break;
}
You are doing the switch statement on the entire array, opposed to a single entry in the array.
Assuming you are trying to write all of the available inputs you could do
string[] General = new string[5];
{
General[0] = "help";
General[1] = "commands";
General[2] = "hello";
General[3] = "info";
General[4] = "quit";
}
foreach(var option in General)
{
switch(option)
{
case "help":
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
break;
}
case "commands":
{
//Do some stuff
break;
}
//etc etc
}
}
The parameter in the switch statement should be the user input, not your optional values, for example:
int input = 0; // get the user input somehow
switch (input)
{
case 0:
{
// Do stuff, and remember to return or break
}
// Other cases
}
Also, this is a perfect use case for an Enum. That would look something like this:
public enum General
{
HELP = 0,
COMMANDS = 1,
HELLO = 2,
INFO = 3,
QUIT = 4
}
int input = 0; // get the user input somehow
switch (input)
{
case General.HELP: //Notice the difference?
{
// Do stuff, and remember to return or break
}
// Other cases
}
This makes your intention very clear, and therefore makes your code more readable and more maintainable. You can't do this with your array, because even though you declare your array in your code, it is still variable and therefore its state at the switch statement is not known at compile time. Enums are immutable, and therefore their values are known at compile time and can be used in switch statements.

Change variable within a C# 'switch' statement

For a school assignment I'm supposed to create a menu kind of like an ATM.
My professor gave us this code to use:
string choice = null;
do
{
Console.Write("[O]pen Account [I]nquire [D]eposit [W]ithdraw [Q]uit: ");
choice = Console.ReadLine();
choice = choice.ToUpper();
switch (choice)
{
case "O": // open an account
case "I": // inquire
case "D": // deposit
case "W": // withdraw
default: break;
}
} while (choice != "Q");
Here is what I did:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string choice = null;
string CustomerName;
Console.WriteLine("Welcome to Fantasy Bank");
Console.Write("Please enter your name:");
CustomerName = Console.ReadLine();
do
{
Console.WriteLine("What can I do for you");
Console.Write("[O]pen Account [I]nquire [D]eposit [W]ithdraw [Q]uit: ");
choice = Console.ReadLine();
choice = choice.ToUpper();
double CurrentBalance = 0;
switch (choice)
{
case "O": // open an account
Console.Write("Name of account holder:");
Console.WriteLine(CustomerName);
Console.Write("Initial Deposit:");
CurrentBalance = Convert.ToDouble(Console.ReadLine()); // i get a major error if someone types in a letter instead of a number
Console.Write("You have succesfully opened an account with an initial deposit of ");
Console.Write(CurrentBalance);
Console.WriteLine(" at an imaginary bank. Congratulations");
break;
case "I": // inquire
Console.Write(CustomerName);
Console.WriteLine("'s Bank Account");
Console.WriteLine(CurrentBalance);
break;
I did a little bit more, but the problem starts here in case "I". CustomerName is getting replaced by what the user types, like it's supposed to be. But CurrentBalance does not change, and I have to set it equal to something otherwise I get an error.
I start to get the feeling that it may be impossible to change a switch variable inside a switch. I looked in my book for passing references/values, but it doesn't include switch in that section.
If y'all could give me a hint what I'm doing wrong or could show me what could fix my problem, that would be great. I'm not expecting code from you, just a little push in the right direction.
Your problem is the placement of your declaration of CurrentBalance.
Currently you have this:
do
{
double CurrentBalance = 0;
switch (choice) {
/* the rest of your code */
}
}
Should be
double CurrentBalance = 0;
do
{
switch (choice) {
/* the rest of your code */
}
}
Now, the next iteration of your do loop does not reset CurrentBalance to 0
Every iteration of the loop you reset CurrentBalance to 0. Move the line double CurrentBalance = 0; :
string choice;
string CurrentName;
double CurrentBalance = 0;
// ...
do
{
// ...
//double CurrentBalance = 0; NOT HERE
switch( ... )
{
}
}
You should initialize all your variables before going into the loop, not in the loop, or else the variable is re-initialized (cleared to 0) every iteration.
double CurrentBalance = 0;
// other code...
do { // ...
I should mention it doesn't have anything to do with changing variables within a switch. Changing variables within a switch is perfectly permissible.

alternative FizzBuzz example error

Been trying to solve this for 2 days now and I just can't get it to work! The programs layout has to stay the same (part of the challenge). Really bugging me and hoping somebody could shed some light...
I keep getting the following error:
Use of unassigned local variable 'countOfFizz'
Use of unassigned local variable 'countOfBuzz'
Use of unassigned local variable 'countOfFizzBuzz'
Use of unassigned local variable 'countOfPrime'
On these lines:
fb.IsFizz(input, countOfFizz);
fb.IsFizz(input, countOfBuzz);
fb.IsFizz(input, countOfFizzBuzz);
fb.IsFizz(input, countOfPrime);
and here is the full code. (again apologies if its poor coding, its basics and the layout has been supplied already).
class FizzBuzz
{
public static void Main()
{
int input;
string enter;
int countOfFizz;
int countOfBuzz;
int countOfFizzBuzz;
int countOfPrime;
Console.WriteLine("Please enter a number: ");
enter = Console.ReadLine();
input = int.Parse(enter);
while (input != 0)
{
Console.WriteLine("Please enter a number: ");
enter = Console.ReadLine();
input = int.Parse(enter);
FizzBuzz fb = new FizzBuzz();
fb.IsFizz(input, countOfFizz);
FizzBuzz fb1 = new FizzBuzz();
fb1.IsBuzz(input, countOfBuzz);
FizzBuzz fb2 = new FizzBuzz();
fb2.IsFizzBuzz(input, countOfFizzBuzz);
FizzBuzz fb3 = new FizzBuzz();
fb3.IsPrime(input, countOfPrime);
FizzBuzz fb4 = new FizzBuzz();
fb4.TotalFizz(countOfFizz);
FizzBuzz fb5 = new FizzBuzz();
fb5.TotalBuzz(countOfBuzz);
FizzBuzz fb6 = new FizzBuzz();
fb6.TotalFizzBuzz(countOfFizzBuzz);
FizzBuzz fb7 = new FizzBuzz();
fb7.TotalPrime(countOfPrime);
}
Console.WriteLine("Finished.");
}
public bool IsFizz(int input, int countOfFizz)
{
if (input % 9 == 0)
{
Console.WriteLine("Fizz");
countOfFizz++;
return true;
}
return false;
}
public bool IsBuzz(int input, int countOfBuzz)
{
if (input % 13 == 0)
{
Console.WriteLine("Buzz");
countOfBuzz++;
return true;
}
return false;
}
public bool IsFizzBuzz(int input, int countOfFizzBuzz)
{
if (input % 9 == 0 && input % 13 == 0)
{
Console.WriteLine("FizzBuzz");
countOfFizzBuzz++;
return true;
}
return false;
}
public bool IsPrime(int input, int countOfPrime)
{
for (int i = 2; i < input; i++)
{
if (input % i == 0 && i != input)
{
return false;
}
}
Console.WriteLine("Prime");
countOfPrime++;
return true;
}
public void BeginTesting(int countOfFizz, int countOfBuzz, int countOfFizzBuzz, int countOfPrime)
{
countOfFizz = 0;
countOfBuzz = 0;
countOfFizzBuzz = 0;
countOfPrime = 0;
}
public int TotalFizz(int countOfFizz)
{
Console.WriteLine("Number of Fizz: ");
return countOfFizz;
}
public int TotalBuzz(int countOfBuzz)
{
Console.WriteLine("Number of Buzz: ");
return countOfBuzz;
}
public int TotalFizzBuzz(int countOfFizzBuzz)
{
Console.WriteLine("Number of FizzBuzz: ");
return countOfFizzBuzz;
}
public int TotalPrime(int countOfPrime)
{
Console.WriteLine("Number of Prime: ");
return countOfPrime;
}
}
The problem is that you are passing ints to the methods, when an int (or float, bool, etc.) is passed to a method it is copied, it is not passed as a reference variable. Therefore, the countOfBuzz you change within a method is not the same as the one in the main method.
To solve this, don't pass those parameters to the methods. Instead, change the scope of those variables to be inside the class instead of inside the main method.
Also, it is good practice to initialize the variables to zero (local variables within methods need to be initialized, otherwise you get that message you asked about).
As Simon already explained in his answer, integers are value types and all value types are always passed by value (by default). This means that when you call for example IsFizz with the countOfFizz then all that happens is that the value of that variable is passed to the function which then has its own variable with a copy of the value. So when the function changes the value, then only that local variable’s value changed but that change will never make it to the original variable.
One way to solve this would be to explicitely pass those variables by reference. You can do this by using ref int countOfFizz in the function signature for the parameter (i.e. add the ref keyword). However, I do not recommend you to do this as it will not provide a state the FizzBuzz class was likely to have.
So, in object oriented programming, you create objects which hold a state. In your case, the FizzBuzz is the class, the type of those objects. Now if we think about it, and take into account that you apparently want to keep count of the number of Fizz/Buzz/FizzBuzz cases, it makes sense to have those counts contained within the object.
So first of all, you should make those countOfX variables instance variables that are bound to the object.
Looking at the IsFizz etc. methods, they are all supposed to return a boolean value. So it’s likely that they were originally only meant to check the input and return true or false depending on if the check succeeded or not. Here we can also increment our counters when we find a falue. So in the end, those methods should only take the input, perform the check, increment their counter and return the check result.
The TotalX methods can then simply return the current counter results, while the BeginTesting method can reset them to zero (without taking any parameters).
Finally, in the Main function you want to create only a single instance of FizzBuzz so we can share the state during the whole duration of the program. You should check the return values for the IsX methods and print the appropriate response here (often you don’t want class types to arbitrarily print stuff but handle that in a different layer—in your case the console application that happens in the Main function).
As a final note, I would like you to know that I’m interpreting a lot into the original task here and cannot perfectly say what the original intention behind this code was. From my point of view it looks a bit ridiculous to do it like that. The FizzBuzz problem, even in this changed instance, is a simple problem aimed to show if a person is capable of basic programming-related thinking. It’s not necessarily meant to be a problem to work on in a complex object oriented manner, but just like the typical “Hello World” there seem to be people who like over-generalizing it in a way to make it terribly complex for fun or practice. I’m not really agreeing that this FizzBuzz instance with that predefined base code is either generalized nor fun nor a good practice. But again, this is just my opinion.
And finally a last hint to complete this “correctly”: The output “FizzBuzz” is the combination of both conditionals for “Fizz” and ”Buzz”. Meaning that if a number qualifies for “FizzBuzz” it also does so for the individual ones. So you should make sure that the check for the individual ones either explicitely prevent the “FizzBuzz” combination to match, or you check for the combined one first and abort further checks if it matches.
Initialize the variables might do the trick for you:
int countOfFizz = 0;
int countOfBuzz = 0;
int countOfFizzBuzz = 0;
int countOfPrime = 0;
Remove the parameter (countOfFizz) from IsFizz, and it should work. Do the same for other similar methods.
public bool IsFizz(int input)
{
if (input % 9 == 0)
{
Console.WriteLine("Fizz");
countOfFizz++;
return true;
}
return false;
}

Categories