I'm new to programming and this class-things are doing my head in.
Here is my code (type is based on userinput)
public static Account CreateAccount(int type)
{
switch (type)
{
case 1:
SaveAcc savings = new SaveAcc();
break;
default:
Console.WriteLine("No such choice");
break;
}
return new Account();
}
These are my classes:
class Account
{
protected int balance;
protected int accountnr = 1;
protected bool credit;
public Account()
{
newNr++;
accountnr = newNr;
}
public override string ToString()
{
return "AccNr: " + Nr.ToString("G") + ", balance: " + balance.ToString("C");
}
}
class SaveAcc: Account
{
public int rate;
public SaveAcc()
{
credit = true;
rate = 0.03;
}
public override string ToString()
{
return "AccNr: " + Nr.ToString("G") + ", balance: " + balance.ToString("C") + credit.ToString();
}
}
When I create a SavAcc object the "wrong" override is being called. My goal is to display all the information given by the override ToString method located in the SavAcc inherited class. Am I missing something obvious?
Change this:
switch (type)
{
case 1:
SaveAcc savings = new SaveAcc();
break;
default:
Console.WriteLine("No such choice");
break;
}
return new Account();
To this:
switch (type)
{
case 1:
return new SaveAcc();
default:
Console.WriteLine("No such choice");
return new Account();
}
Related
EDIT:
The program still does not work as it is supposed to. I tried to implement the suggested changes, which seemed to be the solution indeed. However, now any input into the programme leads to the default statement. What are we doing wrong?
NEW CODE WITH CHANGES BELOW:
public class Processor
{
public void DisplayEmployers()
{
Console.WriteLine("Select an option");
Console.WriteLine("1. Lawyer");
Console.WriteLine("2. Admin");
Console.WriteLine("3. Receptionist");
Console.ReadLine();
}
public enum Staff { Lawyer, Admin, Receptionist, UnsupportedValue }
public void ChooseTypeOfEmployer()
{
Staff s = (Staff.UnsupportedValue);
switch (s)
{
case Staff.Lawyer:
ProvideLogin();
break;
case Staff.Admin:
ProvideLogin();
break;
case Staff.Receptionist:
ProvideLogin();
break;
default:
Console.WriteLine("Invalid input");
break;
}
}
public void ProvideLogin()
{
string username, password;
Console.WriteLine("Please provide username to access the system");
{
Console.WriteLine("Input a username: ");
username = Console.ReadLine();
Console.WriteLine("Input as password: ");
password = Console.ReadLine();
{
Because you already handled all available values.
Try the next case:
public enum Staff { Lawyer, Admin, Receptionist, UnsupportedValue }
public void ChooseTypeOfEmployer()
{
Staff s = (Staff.UnsupportedValue);
switch (s)
{
case Staff.Lawyer:
ProvideLogin();
break;
case Staff.Admin:
ProvideLogin();
break;
case Staff.Receptionist:
ProvideLogin();
break;
default:
Console.WriteLine("Invalid input");
break;
}
}
++ you may to simplify you code
public void ChooseTypeOfEmployer()
{
Staff s = (Staff.UnsupportedValue);
switch (s)
{
case Staff.Lawyer:
case Staff.Admin:
case Staff.Receptionist:
ProvideLogin();
break;
default:
Console.WriteLine("Invalid input");
break;
}
}
i have declared 2 string values eg: ChName1, ChName2 and 2 int values eg: Delay1, Delay2 in the settings.
i would like to implement an array in class so life will be more easier. can somebody correct my code with necessary explanations
public class GetDefaultValues
{
public string Name[int i]
{
get
{
switch (i)
{
case 0:
return Name.Properties.Settings.Default.ChName1;
case 1:
return Name.Properties.Settings.Default.ChName2;
default:
return "Not Implemented";
}
}
set
{
switch (i)
{
case 0:
{
Name.Properties.Settings.Default.ChName1 = value;
break;
}
case 1:
{
Name.Properties.Settings.Default.ChName2 = value;
break;
}
}
Name.Properties.Settings.Default.Save();
}
}
public int Value[int i]
{
get
{
switch (i)
{
case 0:
return Name.Properties.Settings.Default.Delay1;
case 1:
return Name.Properties.Settings.Default.Delay2;
default:
return 0;
}
}
set
{
switch (i)
{
case 0:
{
Name.Properties.Settings.Default.Delay1 = value;
break;
}
case 1:
{
Name.Properties.Settings.Default.Delay2 = value;
break;
}
}
Name.Properties.Settings.Default.Save();
}
}
}
then in my main code i could do like this
GetDefaultValues Vlues = new GetDefaultValues();
Vlues.Name[0] = "SomeName";
string SomeString = Vlues.Name[1];
Vlues.Value[0] = 125;
int SomeInt = Vlues.Value[1];
this code is generating errors in my code.
Error 2 Bad array declarator: To declare a managed array the rank
specifier precedes the variable's identifier. To declare a fixed size
buffer field, use the fixed keyword before the field type
will be happy if i could know why??
please help!!
I would recommend not to use properties for this because properties should not have that logic. You should use methods instead.
This could be look like this for example (just added the name as a sample).
public class GetDefaultValues
{
public bool SetName(int i, string value)
{
switch (i)
{
case 0:
{
Name.Properties.Settings.Default.ChName1 = value;
break;
}
case 1:
{
Name.Properties.Settings.Default.ChName2 = value;
break;
}
default:
return false;
}
Name.Properties.Settings.Default.Save();
return true;
}
public string GetName(int i)
{
switch (i)
{
case 0:
return Name.Properties.Settings.Default.ChName1;
case 1:
return Name.Properties.Settings.Default.ChName2;
default:
return "Not Implemented";
}
}
}
This would be called like this
GetDefaultValues Vlues = new GetDefaultValues();
bool success = Vlues.SetName(0, "SomeName");
string SomeString = Vlues.Name(1);
You can make the SetName method a void method if you don't want to have the info if it worked or not.
I want to create a Banking Application that can handle errors and throw exceptions to handle does errors that occur. These are the Exceptions i want the program to handle :
Withdrawing more than the current balance from an account. This should print an error message.
Attempting a transaction (deposit, withdrawal, or balance) on an account that has not been created yet.
Trying to create more than the maximum number (19) of accounts.
Here is My Code :
using static System.Console;
namespace Bank
{
public partial class Bank : Form
{
public Bank()
{
InitializeComponent();
}
private int _nextIndex = 0;
Accounts[] arrayAccounts = new Accounts[19];
private void createAccountButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(accountIDTexTBox.Text)) return;
var account = new Accounts();
int accountID;
int balance = 0;
bool success = int.TryParse(accountIDTexTBox.Text, out accountID);
if (!int.TryParse(amountTextBox.Text, out balance))
{
result.Text = "Invalid Format in the Amount Fields please correct";
// MessageBox.Show("Invalid Format in the Amount Fields please correct");
}
if (balance < 300)
{
label5.Text = ("initial deposit must be $300 or greater");
}
else if (success)
{
account.AccountId = accountID;
account.Balance = balance;
arrayAccounts[_nextIndex] = account;
OutPutLabel.Text = "Account # " + accountID + " open with balance of " + balance;
}
else
{
result.Text = ("invalid AccountID entered, Please Correct");
}
}
private Accounts GetAccounts(int id)
{
return arrayAccounts.Where(x => x.AccountId == id).FirstOrDefault();
}
private void DepositRadioButton_CheckedChanged(object sender, EventArgs e)
{
// if (string.IsNullOrEmpty(accountIDTexTBox.Text)) return;
int amount = 0;
int accountID;
bool succcess1 = int.TryParse(accountIDTexTBox.Text, out accountID);
bool success2 = int.TryParse(amountTextBox.Text, out amount);
try
{
if (succcess1 && success2 && amount > 0)
{
var selectedAccount = GetAccounts(accountID);
selectedAccount.Balance += amount;
OutPutLabel.Text = "Account # " + accountID + " deposit " + amount;
}
else if (!succcess1)
{
result.Text = "You are attempting to deposit to a non-number ID";
}
else if (!success2)
{
result.Text = "Youu are Attempting to deposit \n "+
"to a non_Number amount \n Please reenter the amount";
}
}
catch(NullReferenceException)
{
result.Text = "Account has not being Created , \n Please create an Account";
}
}
private void WithdrawRadioButton_CheckedChanged(object sender, EventArgs e)
{
// if (string.IsNullOrEmpty(accountIDTexTBox.Text)) return;
int amount = 0;
int accountID;
bool success1 = int.TryParse(accountIDTexTBox.Text, out accountID);
bool success2 = int.TryParse(amountTextBox.Text, out amount);
try
{
if (success1 && success2 && amount > 0)
{
var selectedAccount = GetAccounts(accountID);
selectedAccount.Balance -= amount;
OutPutLabel.Text = amount + " withdraw from account # " + accountID;
}
else if (!success1)
{
result.Text = "You are attempting to withdraw from a non-number ID";
}
else if (!success2)
{
result.Text = "Youu are Attempting to Withdraw \n " +
"a non_Number amount \n Please reenter the amount";
}
}
catch (NullReferenceException)
{
result.Text = "Account has not being created , \n Please Create Account";
}
}
private void exceuteButton_Click(object sender, EventArgs e)
{
/// if (string.IsNullOrEmpty(accountIDTexTBox.Text)) return;
}
private void balanceRadioButton_CheckedChanged(object sender, EventArgs e)
{
int amount = 0;
int accountID;
bool success1 = int.TryParse(accountIDTexTBox.Text, out accountID);
try
{
if (success1)
{
var selectedAccount = GetAccounts(accountID);
OutPutLabel.Text = "Account # " + accountID + " has a balance of " + selectedAccount.Balance;
}
}
catch (NullReferenceException)
{
result.Text = "Account has not being Created"
+ "\n Please create account.";
}
}
}
class NegativeNumberException : Exception
{
private static string msg = "The Amount you enter is a negative number";
public NegativeNumberException() : base(msg)
{
}
}
I have being able to handle some of the errors using TryParse and If/else statements. Is there a better way to handle those errors using Exceptions.
here is the code for Account Class:
public class Accounts
{
public int AccountId { get; set; }
public decimal Balance { get; set; }
public void Deposit(decimal amount)
{
Balance += amount;
}
public void Withdraw(decimal amount)
{
Balance -= amount;
}
}
}
I really need help on handle those errors using exceptions.
First you'll have to create the requested exception types in your code which we will be using later on.
public class InsufficientBalanceException : Exception
{
// Exception for when a user tries to perform a withdrawal/deposit on an account with an insufficient balance of funds.
public InsufficientBalanceException() { }
public InsufficientBalanceException(string message)
: base(message) { }
public InsufficientBalanceException(string message, Exception inner)
: base(message, inner) { }
}
public class InvalidAccountException : Exception
{
// Exception for when a user is trying to perform an operation on an invalid account.
public InvalidAccountException() { }
public InvalidAccountException(string message)
: base(message) { }
public InvalidAccountException(string message, Exception inner)
: base(message, inner) { }
}
public class InvalidNumberOfAccountsException : Exception
{
// Exception for when a user is trying to create an account beyond the given limit.
public InvalidNumberOfAccountsException() { }
public InvalidNumberOfAccountsException(string message)
: base(message) { }
public InvalidNumberOfAccountsException(string message, Exception inner)
: base(message, inner) { }
}
Then, you need to specify in what conditions you'll be throwing each one of those exceptions.
Keep in mind you do not want to do this in your entity class since those are designed to be kept as simple as possible.
You'll most likely want to put that logic into some sort of a helper class (and not in the UI as you display in your code). Regardless, your code should look similar to the following:
public class AccountHelper
{
public Account GetAccount(int accountID)
{
/* Put some logic in here that retrieves an account object based on the accountID.
* Return Account object if possible, otherwise return Null */
return new Account();
}
public bool IsValidAccount(int accountID)
{
/* Put some logic in here that validates the account.
* Return True if account exists, otherwise return False */
return true;
}
public bool IsValidAmount(decimal amount)
{
/* Put some logic in here that validates the amount.
* Return True if amount is valid, otherwise return False */
return amount > 0;
}
public bool IsSufficientAmount(Account account, decimal amount)
{
/* Put some logic in here that validates the requested amount against the given account.
* Return True if account balance is valid, otherwise return False */
if (account == null)
return false;
return account.Balance >= amount;
}
public void DepositToAccount(int accountID, decimal amount)
{
Account account = null;
if (!IsValidAmount(amount))
throw new InvalidAmountException();
if (!IsValidAccount(accountID))
throw new InvalidAccountException();
account = GetAccount(accountID);
account.Deposit(amount);
}
public void WithdrawFromAccount(int accountID, decimal amount)
{
Account account = null;
if (!IsValidAmount(amount))
throw new InvalidAmountException();
if (!IsValidAccount(accountID))
throw new InvalidAccountException();
account = GetAccount(accountID);
if (!IsSufficientAmount(account, amount))
throw new InsufficientBalanceException();
account.Withdraw(amount);
}
}
Additional Notes:
Your Accounts class should be renamed to Account, as each
instance of that object represents one single account.
You should be trying to separate your business logic from the UI. It
is not a good practice to mix things up together as later on you
might face problems in case changes will have to be made. It will be
much easier to locate the required lines of code if you keep all of
your logic in one file and outside the UI.
My code just prints:
welcome to battleship
but the ship coordinates or ship created
and even the end "Press any key to exit"
is not printed.
My suspicion goes to the Constructor, looks like its not called but why my program is counting and not crashing?
Im running the code on a Mac with Xamarin Studio.
Code:
using System;
using System.Collections.Generic;
namespace battleship
{
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("welcome to battleship");
EnumShipClassification.ShipClassification cruiser = EnumShipClassification.ShipClassification.theCruiser;
Coordinate startCoordinate = new Coordinate(5, 5);
EnumDirection.Direction direction = EnumDirection.Direction.west;
Ship ship = new Ship(cruiser, startCoordinate, direction);
Console.WriteLine("ship created"); // #debug
Console.WriteLine("all coords: " + ship.coordinates);
//#end
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
public class Ship
{
public int size; // values from wikipedia
public int amount; // values from wikipedia
public List<Coordinate> coordinates = new List<Coordinate>();
public EnumShipClassification.ShipClassification classification;
public Ship(EnumShipClassification.ShipClassification classification, Coordinate startCoordinate, EnumDirection.Direction toDirection)
{
Console.WriteLine("Ship Constructor called "); // #debug
this.classification = classification;
Console.WriteLine("classification added"); // #debug
switch (classification)
{
case EnumShipClassification.ShipClassification.theBattleship: size = 5; amount = 1; break;
case EnumShipClassification.ShipClassification.theCruiser: size = 4; amount = 2; break;
case EnumShipClassification.ShipClassification.theDestroyer: size = 3; amount = 3; break;
case EnumShipClassification.ShipClassification.theSubmarine: size = 2; amount = 4; break;
default: break;
}
Console.WriteLine("switch ended with size {0} and amout {1}", size, amount);
for (int i = 0; i < size; i++)
{
coordinates.Add(startCoordinate.advancedBy(i, toDirection));
Console.WriteLine("i is: " + i); // #debug
}
}
}
public class EnumDirection
{
public enum Direction
{
north, south, east, west // + all (Direction[] array with content [.n, .s, .e, .w]
}
public Direction[] all = { Direction.north, Direction.south, Direction.east, Direction.west };
}
public class EnumShipClassification
{
public enum ShipClassification // numbers: BoatSize
{
theBattleship = 5, theCruiser = 4, theDestroyer = 3, theSubmarine = 2
}
}
public class Coordinate
{
public int row;
public int column;
private int fieldSize = 10;
public void init()
{
row = 0;
column = 0;
}
public Coordinate invalid = new Coordinate(-1, -1);
public Coordinate(int row, int column)
{
this.row = row;
this.column = column;
}
public Coordinate getRandomCoordinate(int betweenX, int Y)
{
Random r = new Random(fieldSize);
return new Coordinate(r.Next(), r.Next());
}
public Coordinate neighbor(EnumDirection.Direction inDirection)
{
return advancedBy(1, inDirection: inDirection);
}
public Coordinate advancedBy(int displacement, EnumDirection.Direction inDirection)
{
switch (inDirection)
{
case EnumDirection.Direction.north: return new Coordinate(column: column, row: row + displacement);
case EnumDirection.Direction.south: return new Coordinate(column: column, row: row - displacement);
case EnumDirection.Direction.east: return new Coordinate(column: column + displacement, row: row);
case EnumDirection.Direction.west: return new Coordinate(column: column - displacement, row: row);
default: break; // never happens
}
return null; // never happens
}
public string description
{
get
{
return "column: " + column + ", row: " + row;
}
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
try
{
Coordinate _obj = (Coordinate)obj;
return _obj.row == this.row && _obj.column == this.column;
}
catch
{
return false;
}
}
public override int GetHashCode()
{
return 1; // TODO: return a real value
}
public static bool operator ==(Coordinate lhs, Coordinate rhs)
{
return lhs.row == rhs.row && lhs.column == rhs.column;
}
public static bool operator !=(Coordinate lhs, Coordinate rhs)
{
return lhs.row != rhs.row && lhs.column != rhs.column;
}
}
Change
public Coordinate invalid = new Coordinate(-1, -1);
To
public static Coordinate invalid = new Coordinate(-1, -1);
public Coordinate invalid = new Coordinate(-1, -1); causes stack overflow. that's because new Coordinate initialized inside Coordinate class so every time new coordinate must be created. Make the field static so that is created once and can be used for all instances.
You can also add readyonly keyword if the reference is not supposed to change.
public readonly static Coordinate invalid = new Coordinate(-1, -1);
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;
}
}