Skip to content

Commit 7573475

Browse files
committed
LP4 M4 updated instructions, starter code, and solution code
1 parent ec3e8b9 commit 7573475

File tree

5 files changed

+277
-220
lines changed

5 files changed

+277
-220
lines changed

DownloadableCodeProjects/LP4_manage-app-data/Data_M4/Solution/Bank.cs

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,15 @@ public BankAccountNumber(string value)
4747

4848
public record AccountHolderDetails(string Name, string CustomerId, string Address);
4949

50-
// TODO: Task 6: Step 3 - Add the DailyTotal record near the record/type definitions.
51-
public record DailyTotal(DateOnly Day, decimal Total, int Count);
52-
53-
// TODO: Task 4: Step 1 - Add the ILedgerEntry interface near the record/type definitions.
50+
// Task 4: Step 1 - Add the ILedgerEntry interface near the record/type definitions.
5451
public interface ILedgerEntry
5552
{
5653
decimal Amount { get; }
5754
DateTime Date { get; }
5855
string Description { get; }
5956
}
6057

61-
// TODO: Task 4: Step 2 - Update Transaction to implement ILedgerEntry.
58+
// Task 4: Step 2 - Update Transaction to implement ILedgerEntry.
6259
public record Transaction(decimal Amount, DateTime Date, string Description) : ILedgerEntry
6360
{
6461
public override string ToString()
@@ -67,24 +64,8 @@ public override string ToString()
6764
}
6865
}
6966

70-
// TODO: Task 4: Step 3 - Add the generic Ledger<TEntry> class (where TEntry : ILedgerEntry).
71-
public sealed class Ledger<TEntry> where TEntry : ILedgerEntry
72-
{
73-
private readonly List<TEntry> _entries = new();
74-
75-
public IReadOnlyList<TEntry> Entries => _entries;
76-
77-
public void Add(TEntry entry)
78-
{
79-
if (entry is null) throw new ArgumentNullException(nameof(entry));
80-
_entries.Add(entry);
81-
}
82-
83-
public decimal Total() => _entries.Sum(e => e.Amount);
84-
}
85-
86-
// TODO: Task 4: Step 8 - Add a second ledger entry type (e.g., Fee) that implements ILedgerEntry.
87-
public record Fee(decimal Amount, DateTime Date, string Description) : ILedgerEntry;
67+
// Task 6: Step 1 - Add the DailyTotal record near the record/type definitions.
68+
public record DailyTotal(DateOnly Day, decimal Total, int Count);
8869

8970
public class BankAccount
9071
{
@@ -93,13 +74,11 @@ public class BankAccount
9374
public decimal Balance { get; private set; }
9475
public AccountHolderDetails AccountHolder { get; }
9576

96-
// TODO: Task 2: Step 1 - Replace the transactions collection with a private backing field.
97-
// TODO: Task 2: Step 3 - Expose transactions as a read-only generic view (IReadOnlyList<Transaction>).
98-
// TODO: Task 4: Step 5 - Refactor BankAccount to store transactions in Ledger<Transaction>.
77+
// Task 4: Step 4 - Refactor BankAccount to store transactions in Ledger<Transaction>.
9978
private readonly Ledger<Transaction> _ledger = new();
100-
10179
public IReadOnlyList<Transaction> Transactions => _ledger.Entries;
10280

81+
10382
public BankAccount(BankAccountNumber accountNumber, BankAccountType accountType, AccountHolderDetails accountHolder, decimal initialBalance = 0)
10483
{
10584
AccountNumber = accountNumber;
@@ -110,9 +89,8 @@ public BankAccount(BankAccountNumber accountNumber, BankAccountType accountType,
11089

11190
public void AddTransaction(decimal amount, string description)
11291
{
113-
// TODO: Task 2: Step 4 - Update AddTransaction to add to the backing field.
114-
// TODO: Task 4: Step 6 - Update AddTransaction to call _ledger.Add(...) once Ledger<Transaction> is introduced.
11592

93+
// Task 4: Step 5 - Update AddTransaction to call _ledger.Add(...) once Ledger<Transaction> is introduced.
11694
Balance += amount;
11795
_ledger.Add(new Transaction(amount, DateTime.Now, description));
11896
}
@@ -124,20 +102,21 @@ public string DisplayAccountInfo()
124102

125103
public void DisplayTransactions()
126104
{
127-
// TODO: Task 2: Step 5 - Update DisplayTransactions to iterate the public read-only Transactions view.
128-
// TODO: Task 4: Step 7 - Ensure display iterates _ledger.Entries (or the Transactions view backed by it).
129-
130105
Console.WriteLine("Transactions:");
106+
107+
// Task 4: Step 6 - Ensure display iterates _ledger.Entries (or the Transactions view backed by it).
108+
// Task 2: Step 4 - Update DisplayTransactions to iterate the public read-only Transactions view.
131109
foreach (var transaction in Transactions)
132110
{
133111
Console.WriteLine(transaction);
134112
}
135113
}
136114

137-
// TODO: Task 2: Step 6 - (Optional) Add GetTransactions() returning IEnumerable<Transaction>.
115+
// Task 2: Step 5 - Add GetTransactions() returning IEnumerable<Transaction>.
138116
public IEnumerable<Transaction> GetTransactions() => Transactions;
139117

140-
// TODO: Task 6: Step 4 - Add GetDailyTotals() returning IEnumerable<DailyTotal>.
118+
119+
// Task 6: Step 2 - Add GetDailyTotals() returning IEnumerable<DailyTotal>.
141120
public IEnumerable<DailyTotal> GetDailyTotals()
142121
{
143122
return Transactions
@@ -148,8 +127,7 @@ public IEnumerable<DailyTotal> GetDailyTotals()
148127

149128
}
150129

151-
// TODO: Task 3: Step 1 - Add the Bank class that stores accounts in Dictionary<BankAccountNumber, BankAccount>.
152-
130+
// Task 3: Step 1 - Add the Bank class that stores accounts in Dictionary<BankAccountNumber, BankAccount>.
153131
public sealed class Bank
154132
{
155133
private readonly Dictionary<BankAccountNumber, BankAccount> _accounts = new();
@@ -175,7 +153,21 @@ public bool CloseAccount(BankAccountNumber number)
175153
=> _accounts.Remove(number);
176154
}
177155

178-
// TODO: Task 4: Step 3 - Add the generic Ledger<TEntry> class (where TEntry : ILedgerEntry).
156+
// Task 4: Step 3 - Add the generic Ledger<TEntry> class (where TEntry : ILedgerEntry).
157+
public sealed class Ledger<TEntry> where TEntry : ILedgerEntry
158+
{
159+
private readonly List<TEntry> _entries = new();
179160

180-
// TODO: Task 4: Step 8 - Add a second ledger entry type (e.g., Fee) that implements ILedgerEntry.
161+
public IReadOnlyList<TEntry> Entries => _entries;
181162

163+
public void Add(TEntry entry)
164+
{
165+
if (entry is null) throw new ArgumentNullException(nameof(entry));
166+
_entries.Add(entry);
167+
}
168+
169+
public decimal Total() => _entries.Sum(e => e.Amount);
170+
}
171+
172+
// Task 4: Step 7 - Add a second ledger entry type (e.g., Fee) that implements ILedgerEntry.
173+
public record Fee(decimal Amount, DateTime Date, string Description) : ILedgerEntry;

DownloadableCodeProjects/LP4_manage-app-data/Data_M4/Solution/Program.cs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,41 @@ static void Main(string[] args)
99
{
1010
Console.WriteLine("Welcome to the Bank App!");
1111

12-
// TODO: Task 3: Step 3 - Update Program to create a Bank and open 2–3 accounts.
13-
12+
// Task 3: Step 2 - Update Program to create a Bank and open 2 accounts.
1413
var bank = new Bank();
1514

16-
var holder1 = new AccountHolderDetails("Tim Shao", "123456789", "123 Elm Street");
17-
var number1 = new BankAccountNumber("000012345678");
18-
var checking = new BankAccount(number1, BankAccountType.Checking, holder1, 500m);
19-
bank.OpenAccount(checking);
15+
var accountHolderDetails = new AccountHolderDetails("Tim Shao", "123456789", "123 Elm Street");
16+
var accountNumber = new BankAccountNumber("000012345678");
17+
var checking = new BankAccount(accountNumber, BankAccountType.Checking, accountHolderDetails, 500m);
18+
19+
var accountHolderDetails3 = new AccountHolderDetails("Ni Kang", "987654321", "456 Oak Avenue");
20+
var accountNumber3 = new BankAccountNumber("000123456789");
21+
var savings = new BankAccount(accountNumber3, BankAccountType.Savings, accountHolderDetails3, 1200m);
2022

21-
var holder2 = new AccountHolderDetails("Ava Patel", "987654321", "456 Oak Avenue");
22-
var number2 = new BankAccountNumber("000123456789");
23-
var savings = new BankAccount(number2, BankAccountType.Savings, holder2, 1200m);
23+
bank.OpenAccount(checking);
2424
bank.OpenAccount(savings);
2525

2626
// Keep a reference named `bankAccount` for the reporting tasks later in this lab.
2727
var bankAccount = checking;
2828

29-
Console.WriteLine("\nTASK 4: Display basic bank account information");
29+
// Task 3: Step 3 - Retrieve account and perform transactions.
30+
var selected = bank.GetAccount(accountNumber);
31+
selected.AddTransaction(200m, "Deposit");
32+
selected.AddTransaction(-50m, "ATM Withdrawal");
33+
Console.WriteLine(selected.DisplayAccountInfo());
34+
3035
Console.WriteLine($"Account type description: {bankAccount.AccountType.GetDescription()}");
3136
Console.WriteLine(bankAccount.DisplayAccountInfo());
3237

3338
bankAccount.AddTransaction(200m, "Deposit");
3439
bankAccount.AddTransaction(-50m, "ATM Withdrawal");
3540

41+
// Task 4: Step 8 - Add Fee transactions to the account.
3642
var feeLedger = new Ledger<Fee>();
3743
feeLedger.Add(new Fee(-2.50m, DateTime.Now, "Monthly service fee"));
3844
Console.WriteLine($"Fee ledger total: {feeLedger.Total():C}");
3945

46+
// Task 5: Step 1 - Add an anonymous-type transaction report (Select(...) into new { ... }).
4047
var rows = bankAccount.Transactions
4148
.Select(t => new
4249
{
@@ -52,12 +59,15 @@ static void Main(string[] args)
5259
Console.WriteLine($"{row.Date:d} | {row.Kind,-6} | {row.Amount,10:C} | {row.Description}");
5360
}
5461

62+
63+
// Task 6: Step 3 - Update Program to call bankAccount.GetDailyTotals() (named record) for API-friendly reporting.
5564
Console.WriteLine("Daily totals:");
5665
foreach (var day in bankAccount.GetDailyTotals())
5766
{
5867
Console.WriteLine($"{day.Day}: {day.Total:C} ({day.Count} tx)");
5968
}
6069

70+
// Task 5: Step 3 - Add an anonymous-type "top debits" report (Where/OrderBy/Take).
6171
var topDebits = bankAccount.Transactions
6272
.Where(t => t.Amount < 0)
6373
.OrderBy(t => t.Amount)
@@ -70,22 +80,13 @@ static void Main(string[] args)
7080
Console.WriteLine($"{d.Date:d} | {d.Amount,10:C} | {d.Description}");
7181
}
7282

73-
// TODO: Task 5: Step 3 - Add an anonymous-type transaction report (Select(...) into new { ... }).
74-
75-
// TODO: Task 5: Step 5 - Add an anonymous-type daily totals report (GroupBy(...) + Select(...)).
76-
77-
// TODO: Task 5: Step 7 - Add an anonymous-type "top debits" report (Where/OrderBy/Take).
78-
79-
// TODO: Task 6: Step 5 - Update Program to call bankAccount.GetDailyTotals() (named record) for API-friendly reporting.
8083

81-
Console.WriteLine("\nTASK 5: Demonstrate using the Transaction record");
8284
Console.WriteLine(bankAccount.DisplayAccountInfo());
8385
bankAccount.DisplayTransactions();
8486

85-
AccountHolderDetails customer2 = new("Tim Shao", "123456789", "123 Elm Street");
87+
AccountHolderDetails accountHolderDetails2 = new("Tim Shao", "123456789", "123 Elm Street");
8688

87-
Console.WriteLine("\nTASK 6: Demonstrate record comparison and struct immutability");
88-
Console.WriteLine($"Are customers equal? {holder1 == customer2}");
89+
Console.WriteLine($"Are customers equal? {accountHolderDetails == accountHolderDetails2}");
8990

9091
BankAccountNumber accountNumber2 = new BankAccountNumber("000123456789");
9192
Console.WriteLine($"Original Account Number: {accountNumber2}");

DownloadableCodeProjects/LP4_manage-app-data/Data_M4/Starter/Bank.cs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ public BankAccountNumber(string value)
3939

4040
public record AccountHolderDetails(string Name, string CustomerId, string Address);
4141

42-
// TODO: Task 4: Step 1 - Add the ILedgerEntry interface near the record/type definitions.
42+
// Task 4: Step 1 - Add the ILedgerEntry interface near the record/type definitions.
4343

44-
// TODO: Task 4: Step 2 - Update Transaction to implement ILedgerEntry.
44+
45+
// Task 4: Step 2 - Update Transaction to implement ILedgerEntry.
4546
public record Transaction(decimal Amount, DateTime Date, string Description)
4647
{
4748
public override string ToString()
@@ -50,19 +51,22 @@ public override string ToString()
5051
}
5152
}
5253

54+
// Task 6: Step 1 - Add the DailyTotal record near the record/type definitions.
55+
56+
5357
public class BankAccount
5458
{
5559
public BankAccountNumber AccountNumber { get; }
5660
public BankAccountType AccountType { get; }
5761
public decimal Balance { get; private set; }
5862
public AccountHolderDetails AccountHolder { get; }
5963

60-
// TODO: Task 2: Step 2 - Replace the transactions collection with a private backing field.
64+
// Task 4: Step 4 - Refactor BankAccount to store transactions in Ledger<Transaction>.
65+
// Task 2: Step 1 - Replace the transactions collection with a private backing field.
66+
private List<Transaction> Transactions { get; } = new();
6167

62-
// TODO: Task 2: Step 3 - Expose transactions as a read-only generic view (IReadOnlyList<Transaction>).
68+
// Task 2: Step 2 - Expose transactions as a read-only generic view (IReadOnlyList<Transaction>).
6369

64-
// TODO: Task 4: Step 5 - Refactor BankAccount to store transactions in Ledger<Transaction>.
65-
private List<Transaction> Transactions { get; } = new();
6670

6771
public BankAccount(BankAccountNumber accountNumber, BankAccountType accountType, AccountHolderDetails accountHolder, decimal initialBalance = 0)
6872
{
@@ -74,11 +78,11 @@ public BankAccount(BankAccountNumber accountNumber, BankAccountType accountType,
7478

7579
public void AddTransaction(decimal amount, string description)
7680
{
77-
// TODO: Task 2: Step 4 - Update AddTransaction to add to the backing field.
78-
79-
// TODO: Task 4: Step 6 - Update AddTransaction to call _ledger.Add(...) once Ledger<Transaction> is introduced.
8081

82+
// Task 4: Step 5 - Update AddTransaction to call _ledger.Add(...) once Ledger<Transaction> is introduced.
8183
Balance += amount;
84+
85+
// Task 2: Step 3 - Update AddTransaction to add to the backing field.
8286
Transactions.Add(new Transaction(amount, DateTime.Now, description));
8387
}
8488

@@ -89,27 +93,28 @@ public string DisplayAccountInfo()
8993

9094
public void DisplayTransactions()
9195
{
92-
// TODO: Task 2: Step 5 - Update DisplayTransactions to iterate the public read-only Transactions view.
93-
94-
// TODO: Task 4: Step 7 - Ensure display iterates _ledger.Entries (or the Transactions view backed by it).
95-
9696
Console.WriteLine("Transactions:");
97-
foreach (var transaction in Transactions)
97+
98+
// Task 4: Step 6 - Ensure display iterates _ledger.Entries (or the Transactions view backed by it).
99+
// Task 2: Step 4 - Update DisplayTransactions to iterate the public read-only Transactions view.
100+
foreach (Transaction transaction in Transactions)
98101
{
99102
Console.WriteLine(transaction);
100103
}
101104
}
102105

103-
// TODO: Task 2: Step 6 - (Optional) Add GetTransactions() returning IEnumerable<Transaction>.
106+
// Task 2: Step 5 - Add GetTransactions() returning IEnumerable<Transaction>.
107+
108+
109+
// Task 6: Step 2 - Add GetDailyTotals() returning IEnumerable<DailyTotal>.
104110

105-
// TODO: Task 6: Step 4 - Add GetDailyTotals() returning IEnumerable<DailyTotal>.
106111

107112
}
108113

109-
// TODO: Task 3: Step 1 - Add the Bank class that stores accounts in Dictionary<BankAccountNumber, BankAccount>.
114+
// Task 3: Step 1 - Add the Bank class that stores accounts in Dictionary<BankAccountNumber, BankAccount>.
115+
110116

111-
// TODO: Task 4: Step 3 - Add the generic Ledger<TEntry> class (where TEntry : ILedgerEntry).
117+
// Task 4: Step 3 - Add the generic Ledger<TEntry> class (where TEntry : ILedgerEntry).
112118

113-
// TODO: Task 4: Step 8 - Add a second ledger entry type (e.g., Fee) that implements ILedgerEntry.
114119

115-
// TODO: Task 6: Step 3 - Add the DailyTotal record near the record/type definitions.
120+
// Task 4: Step 7 - Add a second ledger entry type (e.g., Fee) that implements ILedgerEntry.

DownloadableCodeProjects/LP4_manage-app-data/Data_M4/Starter/Program.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,41 @@ static void Main(string[] args)
99
{
1010
Console.WriteLine("Welcome to the Bank App!");
1111

12-
// TODO: Task 3: Step 3 - Update Program to create a Bank and open 2–3 accounts.
13-
12+
// Task 3: Step 2 - Update Program to create a Bank and open 2 accounts.
1413
AccountHolderDetails accountHolderDetails = new("Tim Shao", "123456789", "123 Elm Street");
1514
BankAccountNumber accountNumber = new BankAccountNumber("000012345678");
16-
1715
BankAccount bankAccount = new(accountNumber, BankAccountType.Checking, accountHolderDetails, 500m);
1816

17+
// Task 3: Step 3 - Retrieve account and perform transactions.
18+
19+
1920
Console.WriteLine($"Account type description: {bankAccount.AccountType.GetDescription()}");
2021
Console.WriteLine(bankAccount.DisplayAccountInfo());
2122

2223
bankAccount.AddTransaction(200m, "Deposit");
2324
bankAccount.AddTransaction(-50m, "ATM Withdrawal");
2425

25-
// TODO: Task 5: Step 3 - Add an anonymous-type transaction report (Select(...) into new { ... }).
26+
// Task 5: Step 3 - Add an anonymous-type transaction report (Select(...) into new { ... }).
27+
2628

27-
// TODO: Task 5: Step 5 - Add an anonymous-type daily totals report (GroupBy(...) + Select(...)).
29+
// Task 5: Step 5 - Add an anonymous-type daily totals report (GroupBy(...) + Select(...)).
2830

29-
// TODO: Task 5: Step 7 - Add an anonymous-type "top debits" report (Where/OrderBy/Take).
3031

31-
// TODO: Task 6: Step 5 - Update Program to call bankAccount.GetDailyTotals() (named record) for API-friendly reporting.
32+
// Task 5: Step 7 - Add an anonymous-type "top debits" report (Where/OrderBy/Take).
33+
34+
35+
// Task 6: Step 3 - Update Program to call bankAccount.GetDailyTotals() (named record) for API-friendly reporting.
36+
3237

3338
Console.WriteLine(bankAccount.DisplayAccountInfo());
3439
bankAccount.DisplayTransactions();
3540

36-
AccountHolderDetails customer2 = new("Tim Shao", "123456789", "123 Elm Street");
41+
// Task 4: Step 8 - Add Fee transactions to the account.
42+
43+
44+
AccountHolderDetails accountHolderDetails2 = new("Tim Shao", "123456789", "123 Elm Street");
3745

38-
Console.WriteLine($"Are customers equal? {accountHolderDetails == customer2}");
46+
Console.WriteLine($"Are customers equal? {accountHolderDetails == accountHolderDetails2}");
3947

4048
BankAccountNumber accountNumber2 = new BankAccountNumber("000123456789");
4149
Console.WriteLine($"Original Account Number: {accountNumber2}");

0 commit comments

Comments
 (0)