I am writing a simple program in c# which asks the user to enter a number, then tells the user if the number is odd or even. my program works however wheni first enter the number nothing happens, i have to enter the number twice and then it tells me if the number is odd or even, im not very good at using the mvvc technique, so if anyone knows why this is happening and could help me that would be great.my code is below...
class CheckNumber
{
protected String number;
public void SetNumber(String newNumber)
{
number = newNumber;
}
public int Number()
{
int number = Convert.ToInt32(Console.ReadLine());
if (number % 2 == 1) //(number % 2 == 0) would test for even numbers(0 remainder)
{
Console.WriteLine("Odd number");
}
else
{
Console.WriteLine("Even number");
}
return number;
}
}
class CheckNumberController
{
IView view;
CheckNumber checkNumber;
public CheckNumberController(IView theView, CheckNumber theCheckMark)
{
view = theView;
checkNumber = theCheckMark;
}
public void Go()
{
view.Start();
checkNumber.SetNumber(view.GetString("Please enter a number"));
view.Show(checkNumber.Number());
view.Stop();
}
}
class ConsoleView : IView
{
public void Start()
{
Console.Clear();
}
public void Stop()
{
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}
public String GetString(String prompt = "")
{
Console.WriteLine(prompt);
return Console.ReadLine();
}
public Int32 GetInt(String prompt = "")
{
Console.WriteLine(prompt);
return Int32.Parse(Console.ReadLine());
}
public void Show<T>(T message)
{
Console.WriteLine(message);
}
}
interface IView
{
void Start();
void Stop();
String GetString(String prompt);
Int32 GetInt(String prompt);
void Show<T>(T message);
}
class Program
{
static void Main(string[] args)
{
new CheckNumberController(new ConsoleView(), new CheckNumber()).Go();
}
}
You're reading input twice. Firstly in the CheckNumberController.Go()
checkNumber.SetNumber(view.GetString("Please enter a number"));
And secondly in CheckNumber.Number()
int number = Convert.ToInt32(Console.ReadLine());
The latter should be:
int number = Convert.ToInt32(this.number);
As you want to work on the value you've already read and set, not an additional one
public String GetString(String prompt = "")
{
Console.WriteLine(prompt);
//return Console.ReadLine();
return "error is here";
}
When calling GetString() method your again trying to get an input. Just comment and return string if you want.
The key is in this method:
public void Go()
{
view.Start();
checkNumber.SetNumber(view.GetString("Please enter a number"));
view.Show(checkNumber.Number());
view.Stop();
}
SetNumber(string) sets the protected field number in the CheckNumber class. However, when you call view.Show<T>(T), you are calling the Number() method on the CheckNumber class, which ignores the stored variable and reads from the console again.
Related
I've encountered this weird issue that might be connected to my IDE or C# overrall.
Whenever I am inputting something in the console that is being read my Console.ReadLine(), it is being duplicated and shown below until I press return. I want to input a whole String for example, but what I see is reading char by char which kind of messes up debugging and presence of my program. I am attaching the code below along with the screenshot of the issue.
using System;
using System.Text.RegularExpressions;
namespace Zadanie_1
{
class Program
{
static void ShowMenu()
{
Console.WriteLine("Witaj w grze Siszarp!");
Console.WriteLine("[1] Zacznij nową grę");
Console.WriteLine("[X] Zamknij program");
}
static void PickOption(ConsoleKeyInfo keyPressed)
{
switch (keyPressed.KeyChar)
{
case '1':
Console.Clear();
Option1Picked();
break;
case 'X':
Environment.Exit(0);
break;
}
}
static bool IsCharacterNameValid(String characterName)
{
if (characterName.Length < 2)
{
Console.WriteLine("Niepoprawna nazwa!");
return false;
}
if (!Regex.IsMatch(characterName, #"^[a-zA-Z]+$"))
{
Console.WriteLine("Niepoprawna nazwa!");
return false;
}
return true;
}
static void EnterCharacterName()
{
String characterName;
do
{
Console.Write("Podaj nazwę bohatera:");
characterName = Console.ReadLine();
} while (!IsCharacterNameValid(characterName));
}
static void Option1Picked()
{
EnterCharacterName();
}
static void Main(string[] args)
{
ShowMenu();
ConsoleKeyInfo keyPressed = Console.ReadKey();
PickOption(keyPressed);
}
}
}
I'm trying to write a program that consists of some items (only 2 of them for now). It doesn't show any errors in the console, but when I try to call the Main function more than once, it doesn't execute the loops inside. Here's the code by the way.
public static class Program
{
public static string input = Convert.ToString(Console.ReadLine());
public static int health = 100;
public static int energy = 100;
public static void Main()
{
Console.WriteLine("This is a game used for testing items");
Console.WriteLine("Would you like to use items or get them? (Typing in status shows the value of your health and energy)");
if (Program.input == "get")
{
Items.GetItems();
}
if (Program.input == "use")
{
ItemUser();
}
if (Program.input == "status")
{
StatusChecker();
}
}
public static void StatusChecker()
{
Console.WriteLine("Your health is " + Program.health);
Console.WriteLine("Your energy is " + Program.energy);
}
public static void ItemUser()
{
Console.WriteLine("What do you want to use?");
string useChecker = Convert.ToString(Console.ReadLine());
if (useChecker == "healthPotion")
{
health += 100;
Items.healthPotion--;
}
if (useChecker == "energyDrink")
{
energy += 100;
Items.energyDrink--;
}
}
}
public static class Items
{
public static int healthPotion = 0;
public static int energyDrink = 0;
public static void GetItems()
{
Console.WriteLine();
string itemChecker = Convert.ToString(Console.ReadLine());
if ( itemChecker == "health potion")
{
healthPotion++;
Program.Main();
}
if (itemChecker == "energy drink")
{
energyDrink++;
Program.Main();
}
}
So I wanted the program to get the values after updating them, but it just stops after I call Main method more than once. Can anyone help me?
(I'm not that great at coding so I couldn't make really efficient code)
You don't have any loops inside your Main method and every time you run the application you start from scratch and each of your variables contain initial values. If I get right what you're trying to achieve, I would suggest you to write the Main method like this to have loop which will ask a user for a command until the user enters "quit":
static void Main(string[] args)
{
Console.WriteLine("This is a game used for testing items");
while (true)
{
Console.WriteLine("Would you like to use items or get them? (Typing in status shows the value of your health and energy)");
string userAnswer = Console.ReadLine();
if (userAnswer == "quit") break;
if (userAnswer == "get")
{
Items.GetItems();
}
if (userAnswer == "use")
{
ItemUser();
}
if (userAnswer == "status")
{
StatusChecker();
}
}
}
I noticed also that when you call ItemUser method you update static variables of your Items class, but in the StatusChecker method you write to the console variables of your Program class. They are actually different, so I think in your StatusChecker method you may want do the following:
public static void StatusChecker()
{
Console.WriteLine("Your health is " + Items.health);
Console.WriteLine("Your energy is " + Items.energy);
}
You are assigning a variable here:
public static string input = Convert.ToString(Console.ReadLine());
So the next time you call your "Main" method it will use the value you typed in the first time your app executed. If you want it to ask each time you'll need to do something like this:
public static void Main()
{
input = Convert.ToString(Console.ReadLine());
...
}
Another thing is that it can exit after the first call if you type in i.e. "status".
Issue number 3 is that this is not the "nice" way to write a program. The Main method is supposed to be executed when your app starts as it is the entry point (more on that here).
So I'm trying to have the user enter some input which derives its data from a class variable. The user will enter their input though a textbox and hit return when finished, causing the event to update the class variable. However, my issue is figuring out how to send a signal from the EventHandler to continue the process. I know a simple solution would be to put the code triggered inside the event method, but I want to use multiple methods with this textbox and input.
Here's what my code currently looks like:
public partial class Form1 : Form
{
private String input;
public Form1()
{
InitializeComponent();
outbox.AppendText("Hello World!"); //outbox is the display
start();
}
private void inbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
input = inbox.Text; //inbox is the textbox for input;
}
else
{
//do nothing
}
}
private void start()
{
outbox.AppendText("Enter one, two, three or four.");
//---
//this is where the issue arises
//---
if (text_input.Equals("one"))
{
outbox.AppendText("Sunflowers");
}
else if (text_input.Equals("two))
{
outbox.AppendText("Tulips");
}
else if (text_input.Equals("three"))
{
outbox.AppendText("Daisies");
}
else if (text_input.Equals("four"))
{
outbox.AppendText("Poppies");
}
else if (text_input.Equals("quit"))
{
Application.Exit();
}
else
{
outbox.AppendText("Try again.");
start();
}
}
}
What can I do to pause the program until the user hits return and passes a string to input?
You should probably separate the actions before user input from actions that should happen after user input.
If you want to implement different behaviours then it may help to store the program state, including the action you want to perform after user input is complete.
Try something like this, and adapt as required:
public partial class Form1 : Form
{
private String input;
private enum InputMode {
None,
Numbers
}
private class ModeDefinition{
public InputMode Mode {get; private set; }
public string Prompt{get; private set; }
public Action ActionMethod{get; private set; }
public ModeDefinition(InputMode mode, string prompt, Action actionMethod)
{
this.Mode = mode;
this.Prompt = prompt;
this.ActionMethod = actionMethod;
}
}
private InputMode currentMode;
private Dictionary<InputMode,ModeDefinition> modeDefinitions;
public Form1()
{
InitializeComponent();
outbox.AppendText("Hello World!"); //outbox is the display
initialise();
currentMode = InputMode.Numbers;
commenceAction(modeDefinitions[currentMode]);
}
private void initialise(){
modeDefinitions = new Dictionary<InputMode,ModeDefinition>();
var def1 = new ModeDefinition(InputMode.Numbers, "Enter one, two, three or four.", numbersAction);
modeDefinitions.Add(InputMode.Numbers, def1);
}
private void commenceAction(ModeDefinition modeDefinition){
outbox.AppendText(modeDefinition.Prompt);
}
private void inbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
input = inbox.Text; //inbox is the textbox for input;
var currentMode = modeDefinitions[currentMode];
// Execute the mode action
currentMode.ActionMethod();
}
else
{
//do nothing
}
}
private void numbersAction(){
if (text_input.Equals("one"))
{
outbox.AppendText("Sunflowers");
}
else if (text_input.Equals("two))
{
outbox.AppendText("Tulips");
}
else if (text_input.Equals("three"))
{
outbox.AppendText("Daisies");
}
else if (text_input.Equals("four"))
{
outbox.AppendText("Poppies");
}
else if (text_input.Equals("quit"))
{
Application.Exit();
}
else
{
outbox.AppendText("Try again.");
var currentMode = modeDefinitions[currentMode];
outbox.AppendText(modeDefinition.Prompt);
}
}
}
Don't know my solution is what y need
Firstly , u declare property like this
private string _content;
private string content
{
set
{
if (value != _content)
{
_content = value;
checkContent();
}
}
get
{
return _content;
}
}
private void checkContent()
{
if (content.Equals("one"))
{
outbox.AppendText("Sunflowers");
}
else if (content.Equals("two"))
{
outbox.AppendText("Tulips");
}
else if (content.Equals("three"))
{
outbox.AppendText("Daisies");
}
else if (content.Equals("four"))
{
outbox.AppendText("Poppies");
}
else if (content.Equals("quit"))
{
Application.Exit();
}
else
{
outbox.AppendText("Try again.");
start();
}
}
private void start()
{
outbox.AppendText("Enter one, two, three or four.");
}
private void inbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
content = inbox.Text; //inbox is the textbox for input;
}
else
{
//do nothing
}
}
}
Basically I want to launch an event when a string reaches a specific length.
I have a Static String
Static String _Info;
So i have My Delegate that has an integer as a Parameter !
public Delegate void ReachLengthHandler(int Length);
and My event :
public event ReachLengthHandler ReachLengthEvent;
And a Method that Keep addingSome informations to that string :
public void AddInfo()
{
new Thread(() =>
{
while(true)
_Info += ""; //Basically add the inputs of the user here !
if (_Info.Length > 500)
{
if (ReachLengthEvent != null)
ReachLengthEvent(_Info.Length);
}
}).Start();
}
Do you think its the right way to do this event or there are any cleaner ways ?
EDIT :
I want this event because I want to save this string in a Database table row so I don't want to expand the possible size of a row !
As some pointed out in the comments, you may be trying to solve an instance of the XY Problem -- but assuming you're not, you are not approaching things in an object-oriented way, starting with encapsulation.
This could be a start, FWIW:
public class MaxLengthEventArgs : EventArgs
{
public MaxLengthEventArgs(string value)
{
LastAppended = value;
}
public string LastAppended { get; private set; }
}
public delegate void MaxLengthEventHandler(object sender, MaxLengthEventArgs args);
public class StringAccumulator
{
protected StringBuilder Builder { get; private set; }
public StringAccumulator(int maxLength)
{
if (maxLength < 0)
{
throw new ArgumentOutOfRangeException("maxLength", "must be positive");
}
Builder = new StringBuilder();
MaxLength = maxLength;
}
public StringAccumulator Append(string value)
{
if (!string.IsNullOrEmpty(value))
{
var sofar = value.Length + Builder.Length;
if (sofar <= MaxLength)
{
Builder.Append(value);
if ((OnMaxLength != null) && (sofar == MaxLength))
{
OnMaxLength(this, new MaxLengthEventArgs(value));
}
}
else
{
throw new InvalidOperationException("overflow");
}
}
return this;
}
public override string ToString()
{
return Builder.ToString();
}
public int MaxLength { get; private set; }
public event MaxLengthEventHandler OnMaxLength;
}
class Program
{
static void Test(object sender, MaxLengthEventArgs args)
{
var acc = (StringAccumulator)sender;
Console.WriteLine(#"max length ({0}) reached with ""{1}"" : ""{2}""", acc.MaxLength, args.LastAppended, acc.ToString());
}
public static void Main(string[] args)
{
var acc = new StringAccumulator(10);
try
{
acc.OnMaxLength += Test;
acc.Append("abc");
acc.Append("def");
acc.Append("ghij");
Console.WriteLine();
acc.Append("ouch...");
Console.WriteLine("(I won't show)");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
Also, keep in mind that strings in .NET are immutable.
Accumulating them using string concatenation, as you did in
_Info += ""
... isn't going to scale well (performance-wise).
'HTH,
Usually eventhandler is used with specific signature.
public delegate void ReachLengthHandler(object sender, EventArgs args);
class Program
{
public event ReachLengthHandler handler;
private const int Threshhold = 500;
public string Info
{
set
{
if (value.Length > Threshhold)
{
this.OnReachLength(null);
}
}
}
public void OnReachLength(EventArgs args)
{
this.handler?.Invoke(this, args);
}
}
This is my code:
namespace Cinemaseats
{public partial class MainForm : Form
{
private const int numOfSeats = 60;
private int numOfReservedSeats = 0;
Seat currentSeat = new Seat();
public MainForm()
{
InitializeComponent();
InitializeGUI();
}
private void InitializeGUI()
{
radioButton1.Checked = true;
namn.Text = string.Empty;
pris.Text = string.Empty;
}
private void button1_Click(object sender, EventArgs e)
{
**int seatNr = ReadAndValidateSeatNr();**
if (seatNr < 0)
{
MessageBox.Show("Välj ett föremål från listan");
return;
}
if (radioButton2.Checked)
ReserveSeat(seatNr);
else
CancelSeat(seatNr);
UpdateGUI(seatNr);
}
public int GetnumOfSeats()
{
return numOfSeats;
}
**public int ReadAndValidateSeatNr()
{
thelist.Items.Add(test); //test
return;
}
string test = Convert.ToString(2);
}**
}
I have converted my string "test" to an int but still VS says that the return value has to be an int? I want to display 60 "seats in my listbox, that is to say "Seat 1","Seat 2" and so on. I wrote a test string to see if I could make it work.I'm not sure how getter and setters methods work but I have figured otu that I would need them here?
In your ReadAndValidateSeatNr() function you are not returning anything:
public int ReadAndValidateSeatNr()
{
thelist.Items.Add(test); //test
return; //<--------- here nothing is being returned
}
My compiler gives the same error to me :P
Change return to void if you do not need to return anything:
public void ReadAndValidateSeatNr()
{
thelist.Items.Add(test); //test
//return; redundant statement - not even required in this case
}
If your requirement is something like 1 for "Seat 1", etc - go for an enum:
enum my_enum{ Seat1=1, Seat2= 2};
public int ReadAndValidateSeatNr()
{
switch(test)
{
case "Seat 1":
thelist.Items.Add(test); //test
return (int)my_enum.Seat1;
case "Seat 2":
thelist.Items.Add(test); //test
return (int)my_enum.Seat2;
}
}
If you don't want to return something in the ReadAndValidateSeatNr method you should change it like this:
public void ReadAndValidateSeatNr()
{
thelist.Items.Add(test);
}
A method can either return an int or a string (to say only one type). As other have suggested either change the return type to void if you do not want to return any thing.
If your problem is only having "Seat" string at the beginning, then you should not add the item to list box inside the method. Instead return an int from the method and add the item to your list box by doing something like this from the main block.
thelist.Items.Add("Seat " + ReadAndValidateSeatNr().ToString());
In this case your method will be retuning an int and can be used independently and you will still be able to add to your list box in the format you want it.