I currently have a program that makes bank accounts and stores them but I am trying to add code to prevent a user from setting up an account with a negative balance or a balance that exceeds 10,000.
I have declared private decimal balance = 0; in order to set the initial balance to 0 for everyone, it is then later on that they enter the amount they wish to store. What I am trying to do is stop people from creating their account with < 0 OR > 10,000
This is the IF statement I have so far
public virtual bool BalanceRange(decimal amount)
{
if ((balance < 0) || (balance > 10000))
{
return false; //OR message "Amount Not Allowed";
}
this.balance = amount;
return true;
}
The point of this IF statement is to check the amount that the user wishes to store in their bank account, the number is inputted within the Main method as shown below:
public static void Main()
{
CustomerAccount test = new CustomerAccount("Fred", 11000);
Console.WriteLine(test.GetName());
Console.WriteLine(test.GetBalance());
}
What this does is create an account with the Name of Fred and with the amount 11,000. My IF statement should reject the creation of this account as the amount is exceeding the amount I set the if statement to check for(10,000) but that does not seem to be happening and I am not sure why
It may be caused by this. This is the class used for the GetBalance() test so I was thinking that my IF statement needs to be placed within this.
public virtual decimal GetBalance()
{
return this.balance;
}
The constructor:
public interface IAccount
{
bool PayInFunds(decimal amount);
bool WithdrawFunds(decimal amount);
bool BalanceRange(decimal amount);
decimal GetBalance();
string RudeLetterString();
string GetName();
bool SetName(string inName);
}
You're checking the balance before you set it, so it'll be always 0. The check passes, and then you set the illegal number. Check the amount parameter, not the balance field.
public virtual bool BalanceRange(decimal amount)
{
if ((amount < 0) || (amount> 10000))
{
return false; //OR message "Amount Not Allowed";
}
this.balance = amount;
return true;
}
I'm afraid I cannot comment, so this way to ask, where do you even call the BalanceRange method?
I'd expect if even then somewhere in the constructor, but you can't call the constructor, which then rejects to create a object.
You could try something like this in your class with a privat constructor:
public static CustomerAccount AccountFactory(string name, int amount)
{
if ((balance < 0) || (balance >
return null; //OR message "Amount Not Allowed";
return new CustomerAccount(name, amount)
}
Related
The problem I am having is displaying items from my list in ascending order. I understand the problem that is creating this issue which is I am adding caccounts to the List and then adding saccounts to the list but i am not sure of any other way I can do this. The outcome should be to display the accounts in whatever order they were created which is dependent on the user. So as you see by the image below it is storing and displaying all created checking accounts first then savings accounts which is incorrect. It should show the in the order they were created. As you see from the image below the items are out of order. It should show Savings account 1 first then Checking account 2 and so on.
This is the code that is adding the items to this list and is creating the problem
List<Account> accounts = new List<Account>();
accounts.AddRange(caccounts);
accounts.AddRange(saccounts);
foreach (Account account in accounts)
{
List<Transaction> transactions = account.closeMonth();
allTransactions.AddRange(transactions);
}
This code shows the list I am adding saccounts and caccounts to
List<SavingsAccount> saccounts = new List<SavingsAccount>();
List<CheckingAccount> caccounts = new List<CheckingAccount>();
List<Transaction> allTransactions = new List<Transaction>();
This is code that I have in my checking class and savings class that override close month in the abstract account class
public override List<Transaction> closeMonth()
{
var transactions = new List<Transaction>();
var endString = new Transaction();
string reportString = ("Checking account: " + AccountID.ToString() +
" has a balance of $" + endingBalance.ToString());
endString.EndOfMonth = reportString;
transactions.Add(endString);
return transactions;
}
This is the property for the AccountID and i have this in the checking and savings class
class SavingsAccount : Account
{
public override int AccountID { get; set; }
}
When the account is originally created this is the code that assigns the AccountID
if (checkingRadioButton1.Checked == true)
{
_nextIndex++;
transactionLabel5.Text = "Checking Account: #" + _nextIndex +
" created with a starting balance of $" + balance;
accountTextBox1.Text = "" + _nextIndex;
caccounts.Add(new CheckingAccount(balance)
{
AccountID = _nextIndex,
Student = isStudent
});
}
else if (savingsRadioButton2.Checked == true)
{
_nextIndex++;
transactionLabel5.Text = "Savings Account: #" + _nextIndex +
" created with a starting balance of $" + balance;
accountTextBox1.Text = "" + _nextIndex;
saccounts.Add(new SavingsAccount(balance)
{
AccountID = _nextIndex,
Senior = isSenior
});
}
You could use OrderBy on the collection.
var orderedTransactions = allTransactions.OrderBy(x=>x.AccountId).ToList();
Of course you would need to have that CreateDate or whatever property you want ordered by in your object.
Instead of using this code to merge accounts into one list
List<Account> accounts = new List<Account>();
accounts.AddRange(caccounts);
accounts.AddRange(saccounts);
foreach (Account account in accounts)
{
List<Transaction> transactions = account.closeMonth();
allTransactions.AddRange(transactions);
}
you can use this code
List<Account> accounts = new List<Account>();
int saccountsAdded = 0;
int caccountsAdded = 0;
for (int i = 0; i < saccounts.Count + caccounts.Count; i++)
{
if(saccountsAdded == saccounts.Count)
{
accounts[i] = caccounts[caccountsAdded++];
continue;
}
if (caccountsAdded == caccounts.Count)
{
accounts[i] = saccounts[saccountsAdded++];
continue;
}
if (saccounts[saccountsAdded].AccountID > caccounts[caccountsAdded].AccountID)
{
accounts[i] = caccounts[caccountsAdded ++];
}
else
{
accounts[i] = saccounts[saccountsAdded ++];
}
}
In my case, you are sorting accounts when you are combining them and then your accounts list will be ordered.
You can also use the solution from NoSaidTheCompiler, the only difference is that I am sorting and populating the list at the same time and he firstly populates the list and sorts after the list has been populated
The short answer is that you can order your Transactions by the AccountID using the System.Linq extension method OrderBy (along with a .SelectMany method call to flatten each account's transaction list) before you output them:
List<Transaction> transactions = accounts
.OrderBy(a => a.AccountID)
.SelectMany(a => a.closeMonth())
.ToList();
Other thoughts
As I was answering your question, I couldn't figure out why Account was abstract, or why there was a separate class for CheckingAccount and SavingsAccount, because I couldn't see a difference between the two and it felt so redundant to override all these abstract properties and methods with the exact same code in two different classes.
With that in mind, I felt compelled to share some thoughts which may or may not apply to your specific situation. Note that I have never written a banking app before, so there are probably many things I'm not thinkning of - just wanted to share this in case it helps.
Accounts
To me, an account is an account. There may be different rules associated with one type or another, but those can be defined by the Bank that creates the accounts, and the class could have a List<Rule> AccountRules that would be set based on that particular bank's policies (i.e. perhaps there is a minimum balance for a Checking account, but not a Savings account, or they have different interest rate schedules, or something else, but nothing that I can think of that is inherently different).
But in the end, an account is a repository for a decimal amount which can be changed by a Withdrawl or a Deposit (or an Interest accruement).
Transactions
Also, the closeMonth() method seemed really strange to me. It returns a List<Transaction> that contains a single item. Instead, I think an Account should have a List<Transaction> that gets populated from every public method - even balance inquiries. Then this list can be queried to get the activities within a particular time frame, such as a month or a year (by filtering on the Transaction.Timestamp property). Or it could be queried to get different types of transactions (by filtering on the Transaction.TransactionType property).
To simplify adding a new transaction to the list, I added a private AddTransaction method that takes in a Transaction.Type and a description of the transaction. It then creates the Transaction and adds it to the list. Also notice that the Transaction class automatically adds the current DateTime as a Timestamp, so there's no need to worry about that on the client side.
Code
To prevent race conditions where Deposit and Withdrawl are called at the same time from different threads, I added some lock() blocks around any code that accessed Balance.
I also added an override to the ToString method on the Transaction class so that it was easier to output the details of each transaction.
Another item of interest is that you can format a decimal as currency by using the C format string (i.e. if you have decimal balance = 5M; you can do balance.ToString("C") or "{balance:C}" and the string result will be "$5.00" in the U.S. or "£5.00" in England).
So the classes might then look something like the following:
public class Transaction
{
public enum Type { Open, Close, Deposit, Withdrawl, Inquiry, Other }
public Type TransactionType { get; }
public string Description { get; }
public DateTime Timestamp { get; }
public Transaction(Type transactionType, string description)
{
TransactionType = transactionType;
Description = description;
Timestamp = DateTime.Now;
}
public override string ToString()
{
return $"{Timestamp}: {TransactionType} - {Description}";
}
}
public class Account
{
public enum Type { Checking, Savings }
public Type AccountType { get; }
public int Id { get; }
public List<Transaction> Transactions { get; private set; }
private static readonly object IdLock = new object();
private static int _lastAccountId;
private readonly object balanceLock = new object();
private decimal balance;
public Account(decimal initialDeposit, Type accountType)
{
if (initialDeposit < 0)
{
throw new ArgumentOutOfRangeException("initialDeposit cannot be negative");
}
AccountType = accountType;
balance = initialDeposit;
lock (IdLock)
{
Id = ++_lastAccountId;
}
AddTransaction(Transaction.Type.Open,
$"{AccountType} account Id {Id} created with a deposit of: {balance:C}.");
}
public void Deposit(decimal amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException("Deposit amount cannot be negative");
}
lock (balanceLock)
{
balance += amount;
AddTransaction(Transaction.Type.Deposit,
$"{amount} was deposited. New balance: {balance:C}.");
}
}
public void Withdraw(decimal amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException("Withdrawl amount cannot be negative");
}
if (amount > balance)
{
throw new ArgumentOutOfRangeException(
"Cannot withdraw more money than the account contains");
}
lock (balanceLock)
{
balance -= amount;
AddTransaction(Transaction.Type.Withdrawl,
$"{amount} was withdrawn. New balance: {balance:C}.");
}
}
public decimal GetBalance()
{
lock (balanceLock)
{
AddTransaction(Transaction.Type.Inquiry,
$"Balance inquiry made. Balance: {balance:C}.");
return balance;
}
}
private void AddTransaction(Transaction.Type transactionType, string description)
{
if (Transactions == null) Transactions = new List<Transaction>();
Transactions.Add(new Transaction(transactionType, description));
}
}
So, with all that, here's an example that populates a list of accounts in the same order that you have shown in your form above, with an example of how you can output all the transactions for the accounts ordered by the account id:
static void Main(string[] args)
{
// Adding accounts in the same order as they appear on your form
var accounts = new List<Account>
{
new Account(293.05M, Account.Type.Checking),
new Account(293.05M, Account.Type.Checking),
new Account(300M, Account.Type.Savings),
new Account(300M, Account.Type.Savings),
};
// Sort transactions by account Id
List<Transaction> transactions = accounts
.OrderBy(a => a.Id)
.SelectMany(a => a.Transactions)
.ToList();
// Write results to Console
transactions.ForEach(Console.WriteLine);
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
I have a list of customers who owns three bankaccount each (credit, check, retirement) Each bankaccount is a seperate class, with a seperate withdraw method inside. I choose a person in a list (Visual studio) and can by clicking on them see their bankaccount in another list. Now i want to choose one of their account and deposit Money into it, and it is now i get stuck. The money are just beeing depostit to the first bankaccount in the list(index 0)...
I guess i have to compare the account that the customer want to deposit to with the right objects namn in my list (the right account), but cant figure out how i should write this!
the account could also be in different order so i cant just say saving = [0], check [1], retiremet [2],
This is how i call the method
validCustomer = (Customer)lstBankKunder.SelectedItem;
if (radioButtonSaving.IsChecked == true)
{
savingAccount = new SavingsAccount();
savingAccount.DepositMoney(299, valdCustomer);
lstKonton.ItemsSource = null;
lstKonton.ItemsSource = valdCustomer.myBankAccount;
}
And the SavingsAccount class
public override void DepositMoney(int money, Customer validCustomer)
{
savingsaccount = new SavingsAccount();
var item = validCustomer.myBankAccount[savingsaccount.Balance];
item.Balance += money;
validCustomer.myBankAccount[savingsaccount.Balance] = item;
}
I think the error is in your DepositMoney method. You are creating a new savings account, every time the method is called and I guess, that the initial balance is 0. But then you are using this balance to select a bank account:
valdCustomer.myBankAccount[savingsaccount.Balance]
With this logic this would always be the first account in the list.
There are more than one issue with your code. You are creating unnecessary objects of SavingsAccount class at various places.
You haven't shared the code of Customer class so I am not sure what is the type of myBankAccount property.
You need a good way to select a proper account from the customer's multiple account based on the accounttype and then call deposit or withdraw method on that account.
You can use enum for this. Let say you have an enum AccountType as following which identifies the type of account.
public enum AccountType
{
Credit,
Check,
Retirement
}
And then have a property of AccountType in the Account.
public class BankAccount
{
protected double balance;
protected int accountNumber;
protected AccountType accountType;
public BankAccount(int accountNumber, AccountType accountType)
{
this.accountNumber = accountNumber;
this.accountType = accountType;
}
public virtual void DepositMoney(double amount)
{
this.balance += amount;
}
public virtual void WithdrawMoney(double amount)
{
this.balance -= amount;
}
public double Balance
{
get
{
return this.balance;
}
}
public AccountType AccountType
{
get
{
return this.accountType;
}
}
public override string ToString()
{
var output = new StringBuilder();
output.Append(string.Format("Account Number : {0}{1}", this.accountNumber, Environment.NewLine));
output.Append(string.Format("Account Type : {0}{1}", this.accountType, Environment.NewLine));
output.Append(string.Format("Account Balance : {0}{1}", this.balance, Environment.NewLine));
return output.ToString();
}
}
And in Customer class you can have List of accounts to represent the accounts belonging to that customer.
public class Customer
{
private List<BankAccount> accounts;
public Customer()
{
this.accounts = new List<BankAccount>();
}
public string Name {get;set;}
public List<BankAccount> Accounts
{
get
{
return this.accounts;
}
}
public override string ToString()
{
var output = new StringBuilder();
output.Append(string.Format("Customer Name : {0}{1}", this.Name, Environment.NewLine));
output.Append(string.Format("Accounts details {0}", Environment.NewLine));
foreach(var account in this.accounts)
{
output.Append(account.ToString());
}
return output.ToString();
}
}
And then you can locate specific type of account of customer and perform deposit or withdraw operation on it as following.
var checkAccount = customer.Accounts.FirstOrDefault(acct => acct.AccountType == AccountType.Check);
if(checkAccount != null)
{
checkAccount.DepositMoney(3000);
}
FirstOrDefault is an extension method which is part of LINQ. You need to add using System.Linq; in the using directives of the code file whereever you are using it.
Note : The names of class, methods and properties are different in my answer then your class names.
I hope this helps you resolve your issue.
EDIT : Edited the answer to have List of accounts in Customer class instead of Dictionary.
I am creating a program that records data for a sprinter who runs the 100 meters. To do this, I designed a class named the "Entry" class that is used to record the date the user ran the 100m and the seconds that the user ran it in. When an Entry object is created, the user enters the date and seconds, and the objects calculates some other data such as the average speed of the run and the (estimated) top speed. When the user saves the "Entry", the data is written to a file (which contains other entries from previous dates in it). My question is should just the date and seconds be written to the file and the other information (such as average/top speed) be calculated again when the data is loaded from the file? Or should I just write all the data to the file so that the information doesn't need to be calculated again?
Note: A concern I have about writing all the data to the file is that I would have to create some sort of method, likely a constructor, for setting the average/top speed in the entry object (when the data is loaded from the file). This means that someone using this object could set the average/top speed themselves, which I don't want. I want the object itself to be in charge of determining that info, nobody else.
I included some of the code for the class just in case it helps.
Any help or suggestions is greatly appreciated!
class Entry
{
// Class fields
private const int DISTANCE = 100;
private const double ADDEDMPH = 3.5;
private int _month;
private int _day;
private int _year;
private double _seconds;
private double _averageSpeed = 0;
private double _topSpeed;
// Constructors
public Entry()
{ }
public Entry(double secs)
{
_seconds = secs;
validateSeconds();
if(secondsChecked)
calcTopAndAverageSpeed();
}
public Entry(int month, int day, int year)
{
_month = month;
_day = day;
_year = year;
validateDate();
}
public Entry(double secs, int month, int day, int year)
{
_seconds = secs;
_month = month;
_day = day;
_year = year;
validateAll();
if(secondsChecked)
calcTopAndAverageSpeed();
}
// Class properties - when something is entered, it should be checked. If something is invalid, when it is accessed, it should return -1
public double Seconds
{
get
{
if (secondsChecked == true)
return _seconds;
else
return -1;
}
set
{
_seconds = value;
validateSeconds();
if(secondsChecked)
calcTopAndAverageSpeed();
}
}
public int Day
{
get
{
if (dayChecked == true)
return _day;
else
return -1;
}
set
{
_day = value;
validateDay();
}
}
public int Month
{
get
{
if (monthChecked == true)
return _month;
else
return -1;
}
set
{
_month = value;
validateMonth();
}
}
public int Year
{
get
{
if (yearChecked == true)
return _year;
else
return -1;
}
set
{
_year = value;
validateYear();
}
}
// Class Methods
// Calculating methods
void calcAverageSpeed()
{
_averageSpeed = (DISTANCE / _seconds);
}
void calcTopSpeed()
{
_topSpeed = ((DISTANCE / _seconds) + ADDEDMPH);
}
void calcTopAndAverageSpeed()
{
_averageSpeed = (DISTANCE / _seconds);
_topSpeed = _averageSpeed + ADDEDMPH;
}
}
If you are saving all that information in the database, you will need space for it. Also during insertion, you will need to calculate it so insertion will take longer (not significantly longer, but this depends on your performance goals). If you do not save it, then you will need less space but it will need to be calculated during retrieval.
Therefore, it all depends on your requirements. If you do not have any specific requirements, then I would not save it in the database because they can be computed and there is no restriction (requirement) that it should not be computed during retrieval.
Again, depends on the situation.
I don't know if I have chosen a correct headline, but I do hope I have.
I am currently trying to get a better understand of methods in C#, and in doing so I thought that I'd make a simple BankAccount example.
So, what I have is this:
I have three methods:
a method to "deposit" money.
a method to "withdraw" money.
a method to print everything (name, balance).
class BankAccount
{
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private string _Name;
public int Balance
{
get { return _Balance; }
set { _Balance = value; }
}
private int _Balance;
public BankAccount(string name)
{
Name = name;
Balance = 1000;
}
// deposit money
public int Deposit(int balance)
{
Balance += balance;
return Balance;
}
// withdraw money
public int WithDraw(int balance)
{
Balance -= balance;
return Balance;
}
// print to console
public void Print()
{
Console.WriteLine("Owner: " + Name
+ "\nYour current balance is: $" + Balance);
}
}
What I want to do is this:
if I call "deposit" in Main and pass it a value, I want the print method to show me the amount (same goes for "withdraw").
How do I achieve this? I have tried some controle statements, but I don't know how to do this correctly with methods that have parameters?
I hope that someone can shed some light on this issue of mine.
What you can do is overload the method to do more than one thing, for example you can create an overload that takes an int (the balance being subtracted or added) and a string saying which action happening, then you can have this method in the code along with the already existing one
public void Print(int balance, string action)
{
Console.WriteLine("Owner: " + Name
+ "\nYour current balance is: $" + Balance
+ "and you " + action + ": $" + balance);
}
This could be used by passing the string action as "withdrew" or "deposited" depending on which method calls it.
Using this overload allows you to both output the original Print method, if they want to know their balance but never withdrew or deposited, and the new version all depending on which parameters you pass
For more information on overloading see this MSDN page
Example Usage:
public int Deposit(int balance)
{
Balance += balance;
Print(balance, "deposited"); //prints current balance AND action that was completed
return Balance;
}
public void ShowBalance()
{
Print(); //Just prints current balance
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodyGarrettEX3
{
public class Account
{
private long acctNumber;
protected double balance;
public Savings SavingsAccount;
public Checking CheckingAccount;
public Account()
{
this.acctNumber = 1234;
Savings SavingsAccount = new Savings(acctNumber);
Checking CheckingAccount = new Checking(acctNumber);
}
public Account(long newAcctNo)
{
this.acctNumber = newAcctNo;
Savings SavingsAccount = new Savings(newAcctNo);
Checking CheckingAccount = new Checking(newAcctNo);
}
//Members
public long AcctNo
{
get { return AcctNo; }
set { AcctNo = value; }
}
public double Balance
{
get { return balance; }
set { balance = value; }
}
public virtual double Withdrawal(double amount)
{
if ((balance - amount) < 0)
{
PolicyException insufficientFundsException = new PolicyException("Insufficient Funds To Complete This Transaction");
throw insufficientFundsException;
}
return balance;
}
public double Deposit(double amount)
{
balance = balance + amount;
return balance;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodyGarrettEX3
{
public class Savings: Account
{
private double interestRate;
private double minBalance;
public Savings(long newAcctNumber):base(newAcctNumber)
{
balance = 0;
interestRate = 0;
minBalance = 0;
}
//Properties
public double InterestRate //This is a correctional to ensure that the interest rate is always stored as a decimal for math calculations
{
get { return interestRate; }
set
{
if (value > 0)
{
value = value / 100;
}
interestRate = value;
}
}
public double MinBalance
{
get { return minBalance; }
set { minBalance = value; }
}
public override double Withdrawal(double amount)
{
if (minBalance > 0)
{
if (amount > (balance - minBalance))
{
PolicyException minBalanceException = new PolicyException("Insufficient Funds to Complete This Transaction, Exceeds Account Balance and Minimum Balance of Account");
throw minBalanceException;
}
}
else
{
if(amount > (balance - amount))
{
PolicyException insufficientFundsException = new PolicyException("Insufficient Funds to Complete This Transaction, Exceeds Account Balance");
throw insufficientFundsException;
}
}
return balance;
}
}
}
The main issue as it would seem is that upon compilation of the class that manipulates my parent Which is the Account Class is that I get a really odd loop that just goes from the Account Constructor to the Savings Constructor rapidly and then causes a stack overflow.
This happens after the execution of "Account BankAccount = new Account(9999);" in my program testing class.
Thank you so much for your help everyone! I'm really struggling to figure out what is the cause here.
Also, side note I have the constructor built that way due to a requirement in an assignment that mandates we have to have the acctNumber variable pass into the object before it can be created. Even if the object doesn't use the value. However, if this is not possible I am open to anything really.
The loop isn't so odd.
In Savings, you are inheriting from Account. The constructor of Savings also calls the constructor of Account.
The constructor of Account creates a new "Savings" object. The constructor of this new savings object wants to pass data to the constructor of Accounts, which wants to create a new Savings object. Rince and repeat. This will go on and on and on.
It looks like a code smell that the base class (Account) creates (and knows about) the inheriting classes (like Savings).
Edit:
I don't know the details of your requirements, but as I'm looking at this the design is not appropriate for your problem.
You've got your bank account, and this bank account can be a Savings-type account.
class Account
{
protected int _accNr;
public Account()
{
_accnr = 1234;
}
public Account(int accNr)
{
_accNr = accNr;
// only do basic 'account' stuff
}
}
class Savings : Account
{
public Savings() : base()
{
// do other stuff
}
public Savings(int accNr) : base(accNr)
{
// do other stuff
}
}
Now, I've only set up the constructors and nothing else. Point is that now you can either create a Savings class with, or, without an account nr by calling:
Account a = new Savings();
or
Account b = new Savings(9999);
Now, responsabilities are split between account- and savings-classes. The Account class doesn't want to know about inheriting classes and their responsibilities. Through polymorphism we can create Accounts of type 'Savings', but you could also ignore that and do Savings a = new Savings(9999).