Implement polymorphism in a C# app
Polymorphism is a fundamental concept in object-oriented programming that allows you to treat derived classes as instances of their base class. In C#, you can implement polymorphic behavior using interface implementation and class inheritance.
In this exercise, you update an existing app to demonstrate interface-based and inheritance-based polymorphic behavior.
This exercise takes approximately 30 minutes to complete.
Before you start
Before you can start this exercise, you need to:
-
Ensure that you have the latest short term support (STS) version of the .NET SDK installed on your computer. You can download the latest versions of the .NET SDK using the following URL: Download .NET
-
Ensure that you have Visual Studio Code installed on your computer. You can download Visual Studio Code using the following URL: Download Visual Studio Code
-
Ensure that you have the C# Dev Kit configured in Visual Studio Code.
For additional help configuring the Visual Studio Code environment, see Install and configure Visual Studio Code for C# development
Exercise scenario
Suppose you’re helping a non-profit company with a software project. You’ve decided to sharpen your object-oriented programming skills by creating a banking app. You’ve developed an initial version of the app that includes the following files:
-
AccountCalculations.cs: This file contains static utility methods for various financial calculations, such as compound interest, transaction fees, overdraft fees, and currency exchange.
-
BankAccount.cs: This file defines the BankAccount class, implementing the IBankAccount interface and including properties, constructors, methods for account operations, and a copy constructor.
-
BankCustomer.cs: This file defines the BankCustomer class, with properties for first name, last name, and a unique customer ID. It includes methods to return the full name, update the customer’s name, and display customer information. It also maintains a static property for the next customer ID.
-
BankCustomerMethods.cs: This file implements the methods defined in the IBankCustomer interface for the BankCustomer class, including methods to return full name, update name, and display customer information.
-
CheckingAccount.cs: This file defines the CheckingAccount class, which inherits from the BankAccount class and includes properties and methods specific to checking accounts, such as an overdraft limit.
-
Extensions.cs: This file contains extension methods for IBankCustomer and IBankAccount interfaces, providing additional functionality such as validation and greeting. For BankCustomer, it includes methods to check if the customer ID is valid and to greet the customer. For BankAccount, it includes methods to check if the account is overdrawn and if a specified amount can be withdrawn.
-
IBankAccount.cs: This file defines the IBankAccount interface, specifying the properties and methods that a bank account class must implement.
-
IBankCustomer.cs: This file defines the IBankCustomer interface, specifying the properties and methods that a bank customer class must implement.
-
MoneyMarketAccount.cs: This file defines the MoneyMarketAccount class, which inherits from the BankAccount class and includes properties and methods specific to money market accounts, such as a minimum balance requirement.
-
Program.cs: This file contains the main entry point of the application, demonstrating the creation and manipulation of objects created using base and derived classes, as well as various operations like deposits, withdrawals, and transfers.
-
SavingsAccount.cs: This file defines the SavingsAccount class, which inherits from the BankAccount class and includes properties and methods specific to savings accounts, such as a withdrawal limit.
This exercise includes the following tasks:
-
Review the current version of your banking app.
-
Create interfaces that support monthly, quarterly, and yearly reporting.
-
Create classes that support customer and account reporting.
-
Implement interface-based polymorphic behavior using reporting interfaces.
-
Implement inheritance-based polymorphic behavior using the base and derived account classes.
Review the current version of your banking app
In this task, you download the existing version of your banking app and review the code.
Use the following steps to complete this section of the exercise:
-
Download the starter code from the following URL: Implement inheritance and polymorphism - exercise code projects
-
Extract the contents of the LP3SampleApps.zip file to a folder location on your computer.
-
Expand the LP3SampleApps folder, and then open the
Reuse_M2
folder.The Reuse_M2 folder contains the following code project folders:
- Solution
- Starter
The Starter folder contains the starter project files for this exercise.
-
Use Visual Studio Code to open the Starter folder.
-
In the EXPLORER view, collapse the STARTER folder, select SOLUTION EXPLORER, and expand the Reuse_M2 project.
You should see the following project files:
- AccountCalculations.cs
- BankAccount.cs
- BankCustomer.cs
- BankCustomerMethods.cs
- CheckingAccount.cs
- Extensions.cs
- IBankAccount.cs
- IBankCustomer.cs
- MoneyMarketAccount.cs
- Program.cs
- SavingsAccount.cs
-
Take a few minutes to open and review each of the files.
-
AccountCalculations.cs
: This file contains static utility methods for various financial calculations, such as compound interest, transaction fees, overdraft fees, and currency exchange. -
BankAccount.cs
: This file defines the BankAccount class, implementing the IBankAccount interface and including properties, constructors, methods for account operations, and a copy constructor. -
BankCustomer.cs
: This file defines the BankCustomer class, implementing the IBankCustomer interface and including properties, constructors, and a copy constructor. -
BankCustomerMethods.cs
: This file implements the methods defined in the IBankCustomer interface for the BankCustomer class, including methods to return full name, update name, and display customer information. -
CheckingAccount.cs
: This file defines the CheckingAccount class, which inherits from the BankAccount class and includes properties and methods specific to checking accounts. -
Extensions.cs
: This file contains extension methods for IBankCustomer and IBankAccount interfaces, providing additional functionality such as validation and greeting. -
IBankAccount.cs
: This file defines the IBankAccount interface, specifying the properties and methods that a bank account class must implement. -
IBankCustomer.cs
: This file defines the IBankCustomer interface, specifying the properties and methods that a bank customer class must implement. -
MoneyMarketAccount.cs
: This file defines the MoneyMarketAccount class, which inherits from the BankAccount class and includes properties and methods specific to money market accounts. -
Program.cs
: This file contains the main entry point of the application, demonstrating the creation and manipulation of BankCustomer and BankAccount objects, as well as various operations like deposits, withdrawals, and transfers. -
SavingsAccount.cs
: This file defines the SavingsAccount class, which inherits from the BankAccount class and includes properties and methods specific to savings accounts.
-
-
Run the app and review the output in the terminal window.
To run your app, right-click the Reuse_M2 project in the Solution Explorer, select Debug, and then select Start New Instance.
Your app should produce output that’s similar to the following example:
Creating a BankCustomer object for customer Tim Shao... Using derived classes to create bank account objects for Tim Shao... Using inherited properties to display Tim Shao's account information... - Checking account #15206065 has a balance of $500.00 - Savings account #15206066 has a balance of $1,000.00 - Money Market account #15206067 has a balance of $2,000.00 Demonstrating inheritance of the Withdraw, Transfer, and Deposit methods from the base class... - Withdraw 200 from Checking account - Transfer $200.00 from Savings account into Checking account - Deposit $200.00 into Money Market account - Checking account #15206065 has a balance of $500.00 - Savings account #15206066 has a balance of $800.00 - Money Market account #15206067 has a balance of $2,200.00 Demonstrating the use of the 'new' keyword to override a base class method... - Account Number: 15206065, Type: Checking, Balance: $500.00, Interest Rate: 0.00%, Customer ID: 0011540449, Overdraft Limit: 500 - Account Number: 15206066, Type: Savings, Balance: $800.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 1 - Account Number: 15206067, Type: Money Market, Balance: $2,200.00, Interest Rate: 4.00%, Customer ID: 0011540449, Minimum Balance: 1000, Minimum Opening Balance: 2000 Demonstrating specialized Withdraw behavior: CheckingAccount: Attempting to withdraw $600 (within overdraft limit)... Overdraft fee of $5 applied. Account Number: 15206065, Type: Checking, Balance: ($105.00), Interest Rate: 0.00%, Customer ID: 0011540449, Overdraft Limit: 500 CheckingAccount: Attempting to withdraw $1000 (exceeding overdraft limit)... Account Number: 15206065, Type: Checking, Balance: ($105.00), Interest Rate: 0.00%, Customer ID: 0011540449, Overdraft Limit: 500 SavingsAccount: Attempting to withdraw $200 (within withdrawal limit)... Account Number: 15206066, Type: Savings, Balance: $600.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 2 SavingsAccount: Attempting to withdraw $900 (exceeding withdrawal limit)... Account Number: 15206066, Type: Savings, Balance: $600.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 2 SavingsAccount: Exceeding maximum number of withdrawals per month... Attempting to withdraw $50 (withdrawal 1)... Account Number: 15206066, Type: Savings, Balance: $550.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 1 Attempting to withdraw $50 (withdrawal 2)... Account Number: 15206066, Type: Savings, Balance: $500.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 2 Attempting to withdraw $50 (withdrawal 3)... Account Number: 15206066, Type: Savings, Balance: $450.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 3 Attempting to withdraw $50 (withdrawal 4)... Account Number: 15206066, Type: Savings, Balance: $400.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 4 Attempting to withdraw $50 (withdrawal 5)... Account Number: 15206066, Type: Savings, Balance: $350.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 5 Attempting to withdraw $50 (withdrawal 6)... Account Number: 15206066, Type: Savings, Balance: $300.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 6 Attempting to withdraw $50 (withdrawal 7)... Account Number: 15206066, Type: Savings, Balance: $300.00, Interest Rate: 2.00%, Customer ID: 0011540449, Withdrawal Limit: 6, Withdrawals This Month: 6 MoneyMarketAccount: Attempting to withdraw $1000 (maintaining minimum balance)... Account Number: 15206067, Type: Money Market, Balance: $1,200.00, Interest Rate: 4.00%, Customer ID: 0011540449, Minimum Balance: 1000, Minimum Opening Balance: 2000 MoneyMarketAccount: Attempting to withdraw $1900 (exceeding minimum balance)... Account Number: 15206067, Type: Money Market, Balance: $1,200.00, Interest Rate: 4.00%, Customer ID: 0011540449, Minimum Balance: 1000, Minimum Opening Balance: 2000
The customer IDs and account numbers in your output will be different from the example output. Remember that they’re sequential values based on a randomly generated initial value.
Create interfaces that support monthly, quarterly, and yearly reporting
You need to practice implementing interface-based polymorphism, but the existing app relies primarily on class inheritance. You decide to add reporting capabilities to your banking app. The reporting interfaces will define a set of methods that represent monthly, quarterly, and yearly reporting periods. Initially, the interfaces will be implemented by classes that generate reports for bank customers and bank accounts. In the future, the same interfaces could also be applied to other classes, such as bank branches or financial products. This makes the reporting interfaces a good candidate for practicing interface-based polymorphism.
In this task, you create the following interfaces:
- IMonthlyReportable: This interface defines methods for generating reports that cover a full month, a partial month, and a 30 day period.
- IQuarterlyReportable: This interface defines a method for generating a report that covers three month period.
- IYearlyReportable: This interface defines methods for generating reports that cover a full year, a partial year, and a 365 day period.
Use the following steps to complete this section of the exercise:
-
Create a new interface file named
IMonthlyReportGenerator.cs
. -
Update the
IMonthlyReportGenerator.cs
file using the following code:using System; namespace Reuse_M2; public interface IMonthlyReportGenerator { void GenerateMonthlyReport(); // Generates a report for a complete month void GenerateCurrentMonthToDateReport(); // Generates a report for the current month up to the current date void GeneratePrevious30DayReport(); // Generates a report for the previous 30 day period }
-
Create a new interface file named
IQuarterlyReportGenerator.cs
. -
Update the
IQuarterlyReportGenerator.cs
file using the following code:using System; namespace Reuse_M2; public interface IQuarterlyReportGenerator { void GenerateQuarterlyReport(); // Generates a report for a complete three-month period (Jan-Mar, Apr-Jun, Jul-Sep, Oct-Dec) }
-
Create a new interface file named
IYearlyReportGenerator.cs
. -
Update the
IYearlyReportGenerator.cs
file using the following code:using System; namespace Reuse_M2; public interface IYearlyReportGenerator { void GeneratePreviousYearReport(); // Generates a report for the previous year void GenerateCurrentYearToDateReport(); // Generates a report for the current year up to the current date void GenerateLast365DaysReport(); // Generates a report for the previous 365 days }
-
Create a folder under the
Reuse_M2
project namedInterfaces
. -
Move all of your interface files into the
Interfaces
folder.Placing your interface files in a separate folder will help you keep your project organized. You can drag and drop the
IBankAccount.cs
,IBankCustomer.cs
,IMonthlyReportGenerator.cs
,IQuarterlyReportGenerator.cs
, andIYearlyReportGenerator.cs
files into theInterfaces
folder.
Create classes that support customer and account reporting
You need to create classes that implement the reporting interfaces you created in the previous task. The classes will include methods that generate reports for different time periods, such as monthly, quarterly, and yearly reports. The classes will accept a bank customer or bank account object as a parameter and use the object’s properties to generate the reports.
In this task, you create AccountReportGenerator and CustomerReportGenerator classes that implement the reporting interfaces you created in the previous task.
Use the following steps to complete this section of the exercise:
-
Create a new class file named
CustomerReportGenerator.cs
. -
Update the
CustomerReportGenerator.cs
file using the following code:using System; namespace Reuse_M2; public class CustomerReportGenerator : IMonthlyReportGenerator, IQuarterlyReportGenerator, IYearlyReportGenerator { private readonly IBankCustomer _customer; public CustomerReportGenerator(IBankCustomer customer) { _customer = customer; } public void GenerateMonthlyReport() { Console.WriteLine($"Generating monthly report for customer: {_customer.ReturnFullName()}"); // Logic for generating monthly report based on transaction history } public void GenerateCurrentMonthToDateReport() { Console.WriteLine($"Generating current month-to-date report for customer: {_customer.ReturnFullName()}"); // Logic for generating current month-to-date report based on transaction history } public void GeneratePrevious30DayReport() { Console.WriteLine($"Generating previous month report for customer: {_customer.ReturnFullName()}"); // Logic for generating previous month report based on transaction history } public void GenerateQuarterlyReport() { Console.WriteLine($"Generating quarterly report for customer: {_customer.ReturnFullName()}"); // Logic for generating quarterly report based on transaction history } public void GeneratePreviousYearReport() { Console.WriteLine($"Generating previous year report for customer: {_customer.ReturnFullName()}"); // Logic for generating previous year report based on transaction history } public void GenerateCurrentYearToDateReport() { Console.WriteLine($"Generating current year-to-date report for customer: {_customer.ReturnFullName()}"); // Logic for generating current year-to-date report based on transaction history } public void GenerateLast365DaysReport() { Console.WriteLine($"Generating last 365 days report for customer: {_customer.ReturnFullName()}"); // Logic for generating last 365 days report based on transaction history } }
Notice that the
CustomerReportGenerator
class accepts a single parameter of typeIBankCustomer
that it uses to initialize a private read-only field named_customer
. The class implements theIMonthlyReportGenerator
,IQuarterlyReportGenerator
, andIYearlyReportGenerator
interfaces, and it defines a method for each of the methods required by the interfaces. Rather than including the logic for generating actual reports, the methods simply output a message to the console that indicates the type of report and the name of the customer. This is enough to demonstrate that the methods are being called correctly. -
Create a new class file named
AccountReportGenerator.cs
. -
Update the
AccountReportGenerator.cs
file using the following code:using System; namespace Reuse_M2; public class AccountReportGenerator : IMonthlyReportGenerator, IQuarterlyReportGenerator, IYearlyReportGenerator { private readonly IBankAccount _account; public AccountReportGenerator(IBankAccount account) { _account = account; } public void GenerateMonthlyReport() { Console.WriteLine($"Generating monthly report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating monthly report based on transaction history } public void GenerateCurrentMonthToDateReport() { Console.WriteLine($"Generating current month-to-date report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating current month-to-date report based on transaction history } public void GeneratePrevious30DayReport() { Console.WriteLine($"Generating previous month report for for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating previous month report based on transaction history } public void GenerateQuarterlyReport() { Console.WriteLine($"Generating quarterly report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating quarterly report based on transaction history } public void GeneratePreviousYearReport() { Console.WriteLine($"Generating previous year report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating previous year report based on transaction history } public void GenerateCurrentYearToDateReport() { Console.WriteLine($"Generating current year-to-date report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating current year-to-date report based on transaction history } public void GenerateLast365DaysReport() { Console.WriteLine($"Generating last 365 days report for {_account.AccountType} account number: {_account.AccountNumber}"); // Logic for generating last 365 days report based on transaction history } }
Notice that the
AccountReportGenerator
class accepts a single parameter of typeIBankAccount
that it uses to initialize a private read-only field named_account
. The class implements theIMonthlyReportGenerator
,IQuarterlyReportGenerator
, andIYearlyReportGenerator
interfaces, and it defines a method for each of the methods required by the interfaces. Rather than including the logic for generating actual reports, the methods simply output a message to the console that indicates the type of report, the account type, and the account number. This is enough to demonstrate that the methods are being called correctly. -
Create a folder under the
Reuse_M2
project namedServices
. -
Move the
AccountCalculations.cs
,AccountReportGenerator.cs
,CustomerReportGenerator.cs
, andExtensions.cs
files into theServices
folder. -
Create a folder under the
Reuse_M2
project namedModels
. -
Move the
BankAccount.cs
,BankCustomer.cs
,BankCustomerMethods.cs
,CheckingAccount.cs
,MoneyMarketAccount.cs
, andSavingsAccount.cs
files into theModels
folder.
Creating folders that help organize project files makes it easier to find and maintain specific files when you need to make changes. You can organize files by type, such as interfaces, services, and models, or by feature, such as customer-related files, account-related files, and report-related files.
Implement interface-based polymorphic behavior using the reporting interfaces
Interface-based polymorphism allows you to treat objects of different classes as instances of a common interface.
In this task, you’ll use the Program.cs file to demonstrate polymorphic behavior using the reporting classes.
Use the following steps to complete this section of the exercise:
-
Open the Program.cs file.
-
Replace the contents of the Program.cs file with the following code:
using Reuse_M2; using System.Globalization; class Program { static void Main() { } }
-
To demonstrate interface-based polymorphic behavior, add the following code to the
Main
method.// Demonstrate polymorphism using interfaces Console.WriteLine("Demonstrating polymorphism by treating class types as instances of the same interface..."); string firstName = "Sandy"; string lastName = "Zoeng"; // Create an instance of IBankCustomer using BankCustomer IBankCustomer customer1 = new BankCustomer(firstName, lastName); // Create instances of IBankAccount that reference base and derived class types Console.WriteLine("1. Create instances of IBankAccount that reference base and derived class types"); IBankAccount account1 = new BankAccount(customer1.CustomerId, 10000); IBankAccount account2 = new CheckingAccount(customer1.CustomerId, 500, 400); IBankAccount account3 = new SavingsAccount(customer1.CustomerId, 1000); // Demonstrate polymorphism by treating different types of accounts as instances of the same interface. Console.WriteLine("2. Demonstrate polymorphism by treating different types of accounts as instances of the same interface"); Console.WriteLine(account1.DisplayAccountInfo()); Console.WriteLine(account2.DisplayAccountInfo()); Console.WriteLine(account3.DisplayAccountInfo()); // Demonstrate interface-based polymorphism by creating instances of AccountReportGenerator and CustomerReportGenerator Console.WriteLine("\nDemonstrating interface-based polymorphism..."); // Create instances of IReportGenerator using interfaces Console.WriteLine("1. Create instances of IMonthlyReportGenerator, IQuarterlyReportGenerator, and IYearlyReportGenerator that reference CustomerReportGenerator and AccountReportGenerator"); IMonthlyReportGenerator customerMonthlyReportGenerator = new CustomerReportGenerator(customer1); IQuarterlyReportGenerator customerQuarterlyReportGenerator = new CustomerReportGenerator(customer1); IYearlyReportGenerator customerYearlyReportGenerator = new CustomerReportGenerator(customer1); IMonthlyReportGenerator accountMonthlyReportGenerator = new AccountReportGenerator(account1); IQuarterlyReportGenerator accountQuarterlyReportGenerator = new AccountReportGenerator(account1); IYearlyReportGenerator accountYearlyReportGenerator = new AccountReportGenerator(account1); Console.WriteLine("2. Demonstrate polymorphism by showing that different report generators can be used interchangeably through their interfaces."); customerMonthlyReportGenerator.GenerateMonthlyReport(); customerMonthlyReportGenerator.GenerateCurrentMonthToDateReport(); customerMonthlyReportGenerator.GeneratePrevious30DayReport(); customerQuarterlyReportGenerator.GenerateQuarterlyReport(); customerYearlyReportGenerator.GeneratePreviousYearReport(); customerYearlyReportGenerator.GenerateCurrentYearToDateReport(); customerYearlyReportGenerator.GenerateLast365DaysReport(); accountMonthlyReportGenerator.GenerateMonthlyReport(); accountMonthlyReportGenerator.GenerateCurrentMonthToDateReport(); accountMonthlyReportGenerator.GeneratePrevious30DayReport(); accountQuarterlyReportGenerator.GenerateQuarterlyReport(); accountYearlyReportGenerator.GeneratePreviousYearReport(); accountYearlyReportGenerator.GenerateCurrentYearToDateReport(); accountYearlyReportGenerator.GenerateLast365DaysReport();
-
Run the app and verify that your reports are generated correctly.
To run your app, right-click the Reuse_M2 project in the Solution Explorer, select Debug, and then select Start New Instance.
Your app should produce output that’s similar to the following example:
Demonstrating polymorphism by treating class types as instances of the same interface... 1. Create instances of IBankAccount that reference base and derived class types 2. Demonstrate polymorphism by treating different types of accounts as instances of the same interface Account Number: 17283405, Type: Checking, Balance: $10,000.00, Interest Rate: 0.00%, Customer ID: 0015561220 Account Number: 17283406, Type: Checking, Balance: $500.00, Interest Rate: 0.00%, Customer ID: 0015561220, Overdraft Limit: 400 Account Number: 17283407, Type: Savings, Balance: $1,000.00, Interest Rate: 2.00%, Customer ID: 0015561220, Withdrawal Limit: 6, Withdrawals This Month: 0 Demonstrating interface-based polymorphism... 1. Create instances of IMonthlyReportGenerator, IQuarterlyReportGenerator, and IYearlyReportGenerator that reference CustomerReportGenerator and AccountReportGenerator 2. Demonstrate polymorphism by showing that different report generators can be used interchangeably through their interfaces. Generating monthly report for customer: Sandy Zoeng Generating current month-to-date report for customer: Sandy Zoeng Generating previous month report for customer: Sandy Zoeng Generating quarterly report for customer: Sandy Zoeng Generating previous year report for customer: Sandy Zoeng Generating current year-to-date report for customer: Sandy Zoeng Generating last 365 days report for customer: Sandy Zoeng Generating monthly report for Checking account number: 17283405 Generating current month-to-date report for Checking account number: 17283405 Generating previous month report for for Checking account number: 17283405 Generating quarterly report for Checking account number: 17283405 Generating previous year report for Checking account number: 17283405 Generating current year-to-date report for Checking account number: 17283405 Generating last 365 days report for Checking account number: 17283405
Implement inheritance-based polymorphic behavior using the base and derived account classes
Inheritance-based polymorphism allows you to treat derived classes as instances of their base class. In this task, you’ll demonstrate inheritance-based polymorphic behavior using BankAccount and the derived account classes.
Use the following steps to complete this section of the exercise:
-
Take a few minutes to review the BankAccount.cs, CheckingAccount.cs, SavingsAccount.cs, and MoneyMarketAccount.cs files.
-
BankAccount.cs
: This file defines the BankAccount class, implementing the IBankAccount interface and including properties, constructors, methods for account operations, and a copy constructor. -
CheckingAccount.cs
: This file defines the CheckingAccount class, which inherits from the BankAccount class and includes properties and methods specific to checking accounts. -
SavingsAccount.cs
: This file defines the SavingsAccount class, which inherits from the BankAccount class and includes properties and methods specific to savings accounts. -
MoneyMarketAccount.cs
: This file defines the MoneyMarketAccount class, which inherits from the BankAccount class and includes properties and methods specific to money market accounts.
Notice that the derived account classes are designed to support polymorphic behavior. Each derived class overrides the
DisplayAccountInfo
method to provide account-specific information. The derived classes also override theWithdraw
method to implement specialized withdrawal behavior. -
-
Open the Program.cs file.
-
To demonstrate class-based polymorphic behavior, replace the contents of the the Program.cs file with the following code:
using Reuse_M2; using System.Globalization; class Program { static void Main() { // Demonstrate inheritance-based polymorphism Console.WriteLine("\nDemonstrating inheritance-based polymorphism..."); // Create a new customer and accounts for inheritance-based polymorphism Console.WriteLine("Creating BankCustomer and BankAccount objects..."); string firstName = "Tim"; string lastName = "Shao"; BankCustomer customer2 = new BankCustomer(firstName, lastName); // Create accounts for customer1 Console.WriteLine("Creating BankAccount objects for customer1..."); BankAccount bankAccount1 = new BankAccount(customer2.CustomerId, 10000); BankAccount bankAccount2 = new CheckingAccount(customer2.CustomerId, 500, 400); BankAccount bankAccount3 = new SavingsAccount(customer2.CustomerId, 1000); BankAccount bankAccount4 = new MoneyMarketAccount(customer2.CustomerId, 2000); BankAccount[] bankAccounts = new BankAccount[4]; bankAccounts[0] = bankAccount1; bankAccounts[1] = bankAccount2; bankAccounts[2] = bankAccount3; bankAccounts[3] = bankAccount4; // Demonstrate polymorphism by accessing overridden methods from the base class reference Console.WriteLine("\nDemonstrating polymorphism by accessing overridden methods from the base class reference:"); foreach (BankAccount account in bankAccounts) { Console.WriteLine(account.DisplayAccountInfo()); } foreach (BankAccount account in bankAccounts) { if (account is CheckingAccount checkingAccount) { // CheckingAccount: Withdraw within overdraft limit Console.WriteLine("\nCheckingAccount: Attempting to withdraw $600 (within overdraft limit)..."); checkingAccount.Withdraw(600); Console.WriteLine(checkingAccount.DisplayAccountInfo()); // CheckingAccount: Withdraw exceeding overdraft limit Console.WriteLine("\nCheckingAccount: Attempting to withdraw $1000 (exceeding overdraft limit)..."); checkingAccount.Withdraw(1000); Console.WriteLine(checkingAccount.DisplayAccountInfo()); } else if (account is SavingsAccount savingsAccount) { // SavingsAccount: Withdraw within limit Console.WriteLine("\nSavingsAccount: Attempting to withdraw $200 (within withdrawal limit)..."); savingsAccount.Withdraw(200); Console.WriteLine(savingsAccount.DisplayAccountInfo()); // SavingsAccount: Withdraw exceeding limit Console.WriteLine("\nSavingsAccount: Attempting to withdraw $900 (exceeding withdrawal limit)..."); savingsAccount.Withdraw(900); Console.WriteLine(savingsAccount.DisplayAccountInfo()); // SavingsAccount: Exceeding maximum number of withdrawals per month Console.WriteLine("\nSavingsAccount: Exceeding maximum number of withdrawals per month..."); for (int i = 0; i < 7; i++) { Console.WriteLine($"Attempting to withdraw $50 (withdrawal {i + 1})..."); savingsAccount.Withdraw(50); Console.WriteLine(savingsAccount.DisplayAccountInfo()); } } else if (account is MoneyMarketAccount moneyMarketAccount) { // MoneyMarketAccount: Withdraw within minimum balance Console.WriteLine("\nMoneyMarketAccount: Attempting to withdraw $1000 (maintaining minimum balance)..."); moneyMarketAccount.Withdraw(1000); Console.WriteLine(moneyMarketAccount.DisplayAccountInfo()); // MoneyMarketAccount: Withdraw exceeding minimum balance Console.WriteLine("\nMoneyMarketAccount: Attempting to withdraw $1900 (exceeding minimum balance)..."); moneyMarketAccount.Withdraw(1900); Console.WriteLine(moneyMarketAccount.DisplayAccountInfo()); } } } }
Notice that the
Main
method uses a BankCustomer object namedcustomer2
to create four BankAccount objects that reference base and derived account types. The BankAccount objects are stored in an array namedbankAccounts
. The method then demonstrates polymorphism by iterating over thebankAccounts
array and calling theDisplayAccountInfo
method for each account. Despite the array being of type BankAccount, the overriddenDisplayAccountInfo
method of each derived class is called, displaying the specific information for each account type. The method then demonstrates polymorphism by calling theWithdraw
method for each account object, using theis
keyword to check the type of eachaccount
and casting it to the appropriate derived class type. -
Run the app to verify that the BankAccount objects implement the overridden methods in the derived classes as expected.
Demonstrating inheritance-based polymorphism... Creating BankCustomer and BankAccount objects... Creating BankAccount objects for customer1... Demonstrating polymorphism by accessing overridden methods from the base class reference: Account Number: 18662843, Type: Checking, Balance: $10,000.00, Interest Rate: 0.00%, Customer ID: 0018967171 Account Number: 18662844, Type: Checking, Balance: $500.00, Interest Rate: 0.00%, Customer ID: 0018967171, Overdraft Limit: 400 Account Number: 18662845, Type: Savings, Balance: $1,000.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 0 Account Number: 18662846, Type: Money Market, Balance: $2,000.00, Interest Rate: 4.00%, Customer ID: 0018967171, Minimum Balance: 1000, Minimum Opening Balance: 2000 CheckingAccount: Attempting to withdraw $600 (within overdraft limit)... Overdraft fee of $5 applied. Account Number: 18662844, Type: Checking, Balance: ($105.00), Interest Rate: 0.00%, Customer ID: 0018967171, Overdraft Limit: 400 CheckingAccount: Attempting to withdraw $1000 (exceeding overdraft limit)... Account Number: 18662844, Type: Checking, Balance: ($105.00), Interest Rate: 0.00%, Customer ID: 0018967171, Overdraft Limit: 400 SavingsAccount: Attempting to withdraw $200 (within withdrawal limit)... Account Number: 18662845, Type: Savings, Balance: $800.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 1 SavingsAccount: Attempting to withdraw $900 (exceeding withdrawal limit)... Account Number: 18662845, Type: Savings, Balance: $800.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 1 SavingsAccount: Exceeding maximum number of withdrawals per month... Attempting to withdraw $50 (withdrawal 1)... Account Number: 18662845, Type: Savings, Balance: $750.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 2 Attempting to withdraw $50 (withdrawal 2)... Account Number: 18662845, Type: Savings, Balance: $700.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 3 Attempting to withdraw $50 (withdrawal 3)... Account Number: 18662845, Type: Savings, Balance: $650.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 4 Attempting to withdraw $50 (withdrawal 4)... Account Number: 18662845, Type: Savings, Balance: $600.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 5 Attempting to withdraw $50 (withdrawal 5)... Account Number: 18662845, Type: Savings, Balance: $550.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 6 Attempting to withdraw $50 (withdrawal 6)... Account Number: 18662845, Type: Savings, Balance: $550.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 6 Attempting to withdraw $50 (withdrawal 7)... Account Number: 18662845, Type: Savings, Balance: $550.00, Interest Rate: 2.00%, Customer ID: 0018967171, Withdrawal Limit: 6, Withdrawals This Month: 6 MoneyMarketAccount: Attempting to withdraw $1000 (maintaining minimum balance)... Account Number: 18662846, Type: Money Market, Balance: $1,000.00, Interest Rate: 4.00%, Customer ID: 0018967171, Minimum Balance: 1000, Minimum Opening Balance: 2000 MoneyMarketAccount: Attempting to withdraw $1900 (exceeding minimum balance)... Account Number: 18662846, Type: Money Market, Balance: $1,000.00, Interest Rate: 4.00%, Customer ID: 0018967171, Minimum Balance: 1000, Minimum Opening Balance: 2000
Clean up
Now that you’ve finished the exercise, consider archiving your project files for review at a later time. Having your own projects available for review can be a valuable resource when you’re learning to code. Also, building up a portfolio of projects can be a great way to demonstrate your skills to potential employers.