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).
Related
I’m new to coding and has been doing a Junior Software Development Bootcamp for less than a month. Currently, we are learning software fundamentals and C#.
To get in the groove of things and ease into it (as stress-free as possible) I decided to watch an ASMR video on Explaining Object-Oriented Programming with C# and follow along by copying the code into my Visual Studio program.
So here is the problem, I followed along exactly what the developer was typing in the video, however on my Visual Studio program I seem to be getting 2 red squiggly lines on 2 parts of the code I copied.
If someone could help me out here as to why the code is not working, I would be grateful.
This is the whole code
using System;
namespace ExplainingOOP
{
public class Program
{
public static void Main()
{
var checkingAccount = new Account();
}
public class Account {
private const double MAX_ALLOWED_Limit = 100000;
public string AccountOwnerName { get; set; }
private double _balance;
public double Balance { get { return _balance; } }
public void DepositMoney(double amount) {
CheckIfDepositedAmountLooksOkay(amount);
_balance += amount;
}
public void WithdrawMoney(double amount) {
CheckIfBalanceLooksRight(amount);
_balance -= amount;
}
private void CheckIfBalanceLooksRight(double amount) { {
if (_balance == 0)
{
throw new Exception("Insufficient balance");
}
if (_balance < amount)
{
throw new Exception("You are trying to withdraw money more than your balance. Please lower your balance.");
}
if (Balance < 0)
{
throw new Exception("There is something seriously wrong here. Contact the bank teller.");
}
}
if (amount > MAX_ALLOWED_Limit) {
throw new Exception("You cannot depost more than what's allowed daily. Please contact your bank agent for more infomation.");
}
if (amount <= 0) {
throw new Exception("This does not look right. You may not deposit 0 or less amount of money to your account. The eroor is being reported to the bank. Thanks for your patience");
}
}
}
private void CheckIfDepostiedAmountLooksOkay(double amount) {
if (amount > MAX_ALLOWED_LIMIT) {
throw new Exception("You cannot deposit more than what's allowed daily. Please contact your bank agent for more infomation");
}
if (amount <= 0) {
throw new Exception("this does not look right. You may deposit 0 or less amount of money to your account. The error is being reported to your bank. Thanks for your patience.");
}
}
}
}
and this error message i'm getting
/Users/shahzadh/Documents/Software Developer Bootcamp /Projects/ASMR Developer/Explaining Object Oriented Programming with C#/ExplainingOOP/ExplainingOOP/Program.cs(17,17): Error CS0103: The name 'CheckIfDepositedAmountLooksOkay' does not exist in the current context (CS0103) (ExplainingOOP)
/Users/shahzadh/Documents/Software Developer Bootcamp /Projects/ASMR Developer/Explaining Object Oriented Programming with C#/ExplainingOOP/ExplainingOOP/Program.cs(26,26): Error CS0103: The name 'MAX_ALLOWED_LIMIT' does not exist in the current context (CS0103) (ExplainingOOP)
you have a typo into CheckIfDepostiedAmountLooksOkay, so compiler was unable to find method;
You have a wrong case into MAX_ALLOWED_Limit. C# is case-sensitive;
You set curly braces wrong before method CheckIfDepostiedAmountLooksOkay, so this method was outside of the class Account.
The right code would be:
public class Program
{
public static void Main()
{
var checkingAccount = new Account();
}
public class Account
{
private const double MAX_ALLOWED_LIMIT = 100000;
public string AccountOwnerName { get; set; }
private double _balance;
public double Balance
{
get { return _balance; }
}
public void DepositMoney(double amount)
{
CheckIfDepositedAmountLooksOkay(amount);
_balance += amount;
}
public void WithdrawMoney(double amount)
{
CheckIfBalanceLooksRight(amount);
_balance -= amount;
}
private void CheckIfBalanceLooksRight(double amount)
{
{
if (_balance == 0)
{
throw new Exception("Insufficient balance");
}
if (_balance < amount)
{
throw new Exception(
"You are trying to withdraw money more than your balance. Please lower your balance.");
}
if (Balance < 0)
{
throw new Exception("There is something seriously wrong here. Contact the bank teller.");
}
}
if (amount > MAX_ALLOWED_LIMIT)
{
throw new Exception(
"You cannot depost more than what's allowed daily. Please contact your bank agent for more infomation.");
}
if (amount <= 0)
{
throw new Exception(
"This does not look right. You may not deposit 0 or less amount of money to your account. The eroor is being reported to the bank. Thanks for your patience");
}
}
private void CheckIfDepositedAmountLooksOkay(double amount)
{
if (amount > MAX_ALLOWED_LIMIT)
{
throw new Exception(
"You cannot deposit more than what's allowed daily. Please contact your bank agent for more infomation");
}
if (amount <= 0)
{
throw new Exception(
"this does not look right. You may deposit 0 or less amount of money to your account. The error is being reported to your bank. Thanks for your patience.");
}
}
}
}
First of all I would like to know how I might be able to perform calculations for a text file with data such as:
Type Product Price Quantity
regular,bread,2.00,2
regular,milk,2.00,3
I want to perform calculations such as getting the total cost for each one, for each line and then write the results to a new file.
Please note I need it formatted in the structure where Grocery Item is the base class and PurchasedItem and FreshItem are both subclasses, so I need to use the methods on each subclass for calculating.
Note I have tried using test values instead of reading text file values and it seems I cannot retrieve the method from FreshItem Subclass but it works with methods on the PurchasedItem class (i guess this questions is for later, I want to make sure im using a compatible writeAllLines method first that can use subclass methods)
The below sample has missing constructors and is just an example layout
class GroceryItem
{
public void writeFile()
{
List<string> lines = new List<string>(File.ReadAllLines("groceries.txt"));
//regular item cost calculator
PurchasedItem purchasedItem = new PurchasedItem(50,1); //testing to return value to print into the write out file
double cost = purchasedItem.regularCost();
lines.Add(Convert.ToString(cost));
//fresh item cost calculation here
double purchaseCost = purchasedItem.freshItemCost(10,1); //<<<<<<============Trying to add the method from the sub-subclass freshItemCost()
//total items calculation here
//total cost calculation here
// Reads all lines from the file and puts them into the list.
lines.Add("Grocery for you"); // You can add new lines now.
lines.Add(DateTime.Now.ToString());
File.WriteAllLines("c:\\MicrosoftVisual\\invoice.txt", lines);
}
public class PurchasedItem : GroceryItem //inheriting properties from class GroceryItem
{
public double regularCost() //method from cost of regular
{
return this.price * this.quantity * 1.1; //workout out cost for purchases including GST
}
}
public class FreshItem : PurchasedItem //Inheriting properties from class Purchased Item
{
public double freshItemCost(double w, double p) //method to get cost of fresh item
{
return this.weight * this.price; //workout cost of the fresh item excluding GST
}
Try following code to get started :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication108
{
class Program
{
const string FILENAME = "groceries.txt";
static void Main(string[] args)
{
GroceryItem grocery = new GroceryItem();
grocery.ReadFile(FILENAME);
}
}
class GroceryItem
{
public static List<GroceryItem> items = new List<GroceryItem>();
public string _type { get; set; }
public string name { get; set; }
public decimal price { get; set; }
public int quantity { get; set; }
public decimal weight { get; set; }
public void ReadFile(string filename)
{
string line = "";
StreamReader reader = new StreamReader(filename);
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if(line.Length > 0)
{
string[] splitArray = line.Split(new char[] { ',' });
//regular item cost calculator
_type = splitArray[0];
name = splitArray[1];
PurchasedItem purchasedItem = new PurchasedItem(splitArray); //testing to return value to print into the write out file
items.Add(purchasedItem);
}
}
}
public class PurchasedItem : GroceryItem //inheriting properties from class GroceryItem
{
public PurchasedItem(string[] splitArray)
{
this._type = splitArray[0];
this.name = splitArray[1];
this.quantity = int.Parse(splitArray[2]);
this.price = decimal.Parse(splitArray[3]);
}
public decimal regularCost() //method from cost of regular
{
return this.price * this.quantity * (decimal)1.1; //workout out cost for purchases including GST
}
}
}
}
Ok here is how i tried to integrate it, i tried changing the items to string otherwise it would not let me add my method to perform the calculation for the grocery price, however if i changed it or not, when i try adding everything together it seems to come up with an error, here is the code so far:
Sorry that it's probably long and has a bit of unnecessary stuff in: https://dotnetfiddle.net/pBrXwz
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 currently have a listbox that displays the date, type of cake and size. I want to add cost to the listbox, but I am having trouble. It currently displays zero for the cost. The cost is displayed in a label (lblRoundCost). I have a base class named Cake and two subclasses RoundCake and SquareCake. I'm not sure if this code is correct for the base class:
class Cake
{
private const int CostOfFoodPerPerson = 25;
public int size;
private bool chocolateIcing;
protected DateTime cakeDate;
decimal cost;
public Cake(int numberOfPeople, bool chocolateIcing, DateTime cakeDate)
{
this.chocolateIcing = chocolateIcing;
Size = size;
this.cakeDate = cakeDate;
Cost = cost;
}
public virtual decimal Cost
{
get { return cost; }
set { cost = value; }
}
public virtual int Size
{
get { return size; }
set { size = value; }
}
public virtual bool ChocolateIcing
{
set { chocolateIcing = value; }
}
public virtual decimal CalculateCost()
{
decimal CostOfIcing = 0;
if (chocolateIcing)
CostOfIcing = (Size * 1.5M) + 10M;
else
CostOfIcing = 0;
decimal TotalCost = CostOfIcing + CostOfFoodPerPerson;
return TotalCost;
}
public DateTime CakeDate
{
set { cakeDate = value; }
}
}
}
RoundCake code
class RoundCake : Cake
{
bool fruitOption;
public RoundCake(int size, bool fruitOption, bool chocolateIcing, DateTime cakeDate)
: base(size, chocolateIcing, cakeDate)
{FruitOption = fruitOption;}
public bool FruitOption
{
set { fruitOption = value; }
}
public override decimal CalculateCost()
{
decimal totalCost;
if (fruitOption)
{
totalCost = base.CalculateCost();
return totalCost + (totalCost * .05M);
}
else
{
totalCost = base.CalculateCost() ;
return totalCost;
}
}
public override string ToString()
{
return String.Format("{0,-20}{1,2}{2,20}{2,20}", cakeDate.ToShortDateString(), "RC",Size,Cost);
}
Form1 code
private void btnRound_Click_1(object sender, EventArgs e)
{
lstCake.Items.Add(roundCake);
}
roundCake = new RoundCake((int)nudRound.Value, chbFruit.Checked, chbChocoRound.Checked,
dtpRound.Value.Date);
lblRoundCost.Text = roundCake.CalculateCost().ToString("c");
The reason you're seeing 0 is because you never actually assign anything to Cost, and the default for decimal is 0.
Here's what's happening:
In your base constructor, you have:
Cost = cost;
However, cost is never initialized in the class and it's not passed in via the constructor. So in the base it's 0.
The same thing happens with the inheriting class - Cost is never specified, so it's still going to be 0 (even if there wasn't a base class, it'd still be 0).
Now, in this line of code:
lblRoundCost.Text = roundCake.CalculateCost().ToString("c");
You're assigning the value calculated by CalculateCost() to the Label, but you're never persisting that value in the the class:
public override decimal CalculateCost()
{
decimal totalCost;
if (fruitOption)
{
totalCost = base.CalculateCost();
return totalCost + (totalCost * .05M);
}
else
{
totalCost = base.CalculateCost() ;
return totalCost;
}
}
You're returning a value, but not assigning it to the class member cost. The base implementation does the same thing.
There a number of ways to solve this. Here's one (this is a pretty simple one, and to be honest it has a bit of a code smell to me, but it'll server as an example):
Modify the CalculateCost() method to update the cost field:
public virtual void CalculateCost()
{
decimal CostOfIcing = 0;
if (chocolateIcing)
CostOfIcing = (Size * 1.5M) + 10M;
else
CostOfIcing = 0;
decimal cost = CostOfIcing + CostOfFoodPerPerson;
}
Note that this doesn't return a type anymore (you may have it still do so, it really depends a lot on your overall design, so pick the path that works best for your design). Don't forget to make this change in the inheriting class's implementation as well.
Now you simply need to call the CalculateCost() method and you will have the cost available, and you can use the property to get the cost for assignment to Labels or whatever else you need, and it will show up in your overridden ToString() method.
Again, there are multiple ways to solve this, and they depend on a mix of OOP principles and your design needs. My main intention with this answer was to demonstrate why cost was showing up as zero.