• c#关于类,对象的例子实现


    此文是根据类和对象 - C# 基础教程 | Microsoft Learn进行实践的笔记。

    一.题目

    BankAccount 类表示银行帐户。对账户进行分类

    1. 用一个 10 位数唯一标识银行帐户。
    2. 用字符串存储一个或多个所有者名称。
    3. 可以检索余额。
    4. 接受存款。
    5. 接受取款。
    6. 初始余额必须是 >=0
    7. 取款后的余额不能是负数。(信用卡除外)

    二.代码实现

    2.1 Transaction类

    2.1.1 全类完整代码:

    此类用来记录每笔流水

    1. namespace Classes;
    2. public class Transaction
    3. {
    4. public decimal Amount { get; }
    5. public DateTime Date { get; }
    6. public string Notes { get; }
    7. public Transaction(decimal amount, DateTime date, string note)
    8. {
    9. Amount = amount;
    10. Date = date;
    11. Notes = note;
    12. }
    13. }

    2.2 BankAccount 类

    2.2.1 全类完整代码:

    1. namespace Classes;
    2. public class BankAccount
    3. {
    4. // 用一个 10 位数唯一标识银行帐户。
    5. //用字符串存储一个或多个所有者名称。
    6. //可以检索余额。
    7. //接受存款。
    8. //接受取款。
    9. //初始余额必须是正数。
    10. //取款后的余额不能是负数。
    11. private static int accountNumberSeed = 1234567890;
    12. private readonly decimal _minimumBalance;
    13. public string Number { get; }
    14. public string Owner { get; set; }
    15. public decimal Balance { get
    16. {
    17. decimal balance = 0;
    18. foreach (var item in allTransactions)
    19. {
    20. balance += item.Amount;
    21. }
    22. return balance;
    23. }
    24. }
    25. //public BankAccount(string name, decimal initialBalance)
    26. //{
    27. // this.Owner = name;
    28. // this.Number = accountNumberSeed.ToString();
    29. // accountNumberSeed++;
    30. // MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
    31. //}
    32. public BankAccount(string name, decimal initialBalance) : this(name, initialBalance, 0) { }
    33. public BankAccount(string name, decimal initialBalance, decimal minimumBalance)
    34. {
    35. Number = accountNumberSeed.ToString();
    36. accountNumberSeed++;
    37. Owner = name;
    38. _minimumBalance = minimumBalance;
    39. if (initialBalance > 0)
    40. MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
    41. }
    42. ///
    43. /// virtual 关键字在基类中声明一个方法,让派生类可以为该方法提供不同的实现。 在 virtual 方法种,任何派生类都可以选择重新实现。
    44. /// 派生类使用 override 关键字定义新的实现。 通常将其称为“重写基类实现”。 virtual 关键字指定派生类可以重写此行为。
    45. /// 还可以声明 abstract 方法,让派生类必须在其中重写此行为。 基类不提供 abstract 方法的实现。
    46. ///
    47. public virtual void PerformMonthEndTransactions() { }
    48. private List allTransactions = new List();
    49. public void MakeDeposit(decimal amount, DateTime date, string note)
    50. {
    51. if (amount <= 0)
    52. {
    53. throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
    54. }
    55. var deposit = new Transaction(amount, date, note);
    56. allTransactions.Add(deposit);
    57. }
    58. //public void MakeWithdrawal(decimal amount, DateTime date, string note)
    59. //{
    60. // if (amount <= 0)
    61. // {
    62. // throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    63. // }
    64. // if (Balance - amount < _minimumBalance)
    65. // {
    66. // throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    67. // }
    68. // var withdrawal = new Transaction(-amount, date, note);
    69. // allTransactions.Add(withdrawal);
    70. //}
    71. public void MakeWithdrawal(decimal amount, DateTime date, string note)
    72. {
    73. if (amount <= 0)
    74. {
    75. throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    76. }
    77. Transaction? overdraftTransaction = CheckWithdrawalLimit(Balance - amount < _minimumBalance);
    78. Transaction? withdrawal = new(-amount, date, note);
    79. allTransactions.Add(withdrawal);
    80. if (overdraftTransaction != null)
    81. allTransactions.Add(overdraftTransaction);
    82. }
    83. protected virtual Transaction? CheckWithdrawalLimit(bool isOverdrawn)
    84. {
    85. if (isOverdrawn)
    86. {
    87. throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    88. }
    89. else
    90. {
    91. return default;
    92. }
    93. }
    94. public string GetAccountHistory()
    95. {
    96. var report = new System.Text.StringBuilder();
    97. decimal balance = 0;
    98. report.AppendLine("Date\t\tAmount\tBalance\tNote");
    99. foreach (var item in allTransactions)
    100. {
    101. balance += item.Amount;
    102. report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
    103. }
    104. return report.ToString();
    105. }
    106. }

    2.2.2 具体讲解:

     其中包含了银行账户号码,用户,余额,以及此张卡最小的金额数(当卡是信用卡的时候,欠的金额后的余额)这四个属性。

    1. private static int accountNumberSeed = 1234567890;
    2. private readonly decimal _minimumBalance;
    3. public string Number { get; }
    4. public string Owner { get; set; }
    5. public decimal Balance { get
    6. {
    7. decimal balance = 0;
    8. foreach (var item in allTransactions)
    9. {
    10. balance += item.Amount;
    11. }
    12. return balance;
    13. }
    14. }

     MakeWithdrawal取钱,MakeDeposit存钱

    存钱和取钱的时候需要确保存钱的金额是大于0的,不然抛出异常。

    取钱的特殊处理是,在信用卡有时候可以借钱,余额为负数只要在额度内,还可以借钱,不收费。但是如果超过了额度,仍然可以借钱,但是需要收取费用。这里的有两笔交易,交易可以为空,或者生成一个Transation的对象(因为计算余额的时候,是遍历Transaction的金额并进行相加)

    1. Transaction? overdraftTransaction = CheckWithdrawalLimit(Balance - amount < _minimumBalance);
    2. Transaction? withdrawal = new(-amount, date, note);

    这样返回的有时候是null,有时候是一个Transaction的对象。

    注意这个CheckWithdrawalLimit在LineOfCreditAccount类中重写了。

    这里CheckWithdrawalLimit 添加的方法是 protected,这意味着只能从派生类中调用它。 该声明会阻止其他客户端调用该方法。 它还是 virtual 的,因此派生类可以更改行为。 返回类型为 Transaction?。    ? 批注指示该方法可能返回 null。 

    1. private List allTransactions = new List();
    2. public void MakeDeposit(decimal amount, DateTime date, string note)
    3. {
    4. if (amount <= 0)
    5. {
    6. throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
    7. }
    8. var deposit = new Transaction(amount, date, note);
    9. allTransactions.Add(deposit);
    10. }
    11. //public void MakeWithdrawal(decimal amount, DateTime date, string note)
    12. //{
    13. // if (amount <= 0)
    14. // {
    15. // throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    16. // }
    17. // if (Balance - amount < _minimumBalance)
    18. // {
    19. // throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    20. // }
    21. // var withdrawal = new Transaction(-amount, date, note);
    22. // allTransactions.Add(withdrawal);
    23. //}
    24. public void MakeWithdrawal(decimal amount, DateTime date, string note)
    25. {
    26. if (amount <= 0)
    27. {
    28. throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    29. }
    30. Transaction? overdraftTransaction = CheckWithdrawalLimit(Balance - amount < _minimumBalance);
    31. Transaction? withdrawal = new(-amount, date, note);
    32. allTransactions.Add(withdrawal);
    33. if (overdraftTransaction != null)
    34. allTransactions.Add(overdraftTransaction);
    35. }
    36. protected virtual Transaction? CheckWithdrawalLimit(bool isOverdrawn)
    37. {
    38. if (isOverdrawn)
    39. {
    40. throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    41. }
    42. else
    43. {
    44. return default;
    45. }
    46. }

    BankAccount()构造函数是与类同名的成员。 用于初始化相应类类型的对象。会根据参数选择不同的构造方法,这称作构造函数的重载。   (构造方法具体可以参考:(7条消息) 什么是构造方法,构造方法的特征,作用_羡羡ˇ的博客-CSDN博客_什么是构造方法?构造方法有哪些特点?

    1. public BankAccount(string name, decimal initialBalance) : this(name, initialBalance, 0) { }
    2. public BankAccount(string name, decimal initialBalance, decimal minimumBalance)
    3. {
    4. Number = accountNumberSeed.ToString();
    5. accountNumberSeed++;
    6. Owner = name;
    7. _minimumBalance = minimumBalance;
    8. //初始余额大于0等于你存进了第一笔钱
    9. if (initialBalance > 0)
    10. MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
    11. }

    第一个构造函数适用于储蓄卡

    第二个适用于借记卡

    1. public string GetAccountHistory()
    2. {
    3. var report = new System.Text.StringBuilder();
    4. decimal balance = 0;
    5. report.AppendLine("Date\t\tAmount\tBalance\tNote");
    6. foreach (var item in allTransactions)
    7. {
    8. balance += item.Amount;
    9. report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
    10. }
    11. return report.ToString();
    12. }

    上面  记录所有交易

    2.3 不同类型的帐户的类

    分为此三类

    • 在每个月的月末获得利息的红利帐户。
    • 余额可以为负,但存在余额时会产生每月利息的信用帐户。
    • 以单笔存款开户且只能用于支付的预付礼品卡帐户。 可在每月初重新充值一次。

    其中的每个类都从其共享的基类( BankAccount 类)继承共享的行为。 为的每个派生类中的新增和不同功能编写实现。 这些派生类已具有 BankAccount 类中定义的所有行为。

     virtual 关键字在基类中声明一个方法,让派生类可以为该方法提供不同的实现。 在 virtual 方法种,任何派生类都可以选择重新实现。 派生类使用 override 关键字定义新的实现。 通常将其称为“重写基类实现”。 virtual 关键字指定派生类可以重写此行为。 还可以声明 abstract 方法,让派生类必须在其中重写此行为。 基类不提供 abstract 方法的实现。

    2.3.1 InterestEarningAccount 

    1. using Classes;
    2. //红利帐户:
    3. //将获得月末余额 5 % 的额度
    4. public class InterestEarningAccount : BankAccount
    5. {
    6. public InterestEarningAccount(string name, decimal initialBalance) : base(name, initialBalance)
    7. {
    8. }
    9. ///
    10. /// 派生类使用 override 关键字定义新的实现
    11. ///
    12. public override void PerformMonthEndTransactions()
    13. {
    14. if (Balance > 500m)
    15. {
    16. decimal interest = Balance * 0.05m;
    17. MakeDeposit(interest, DateTime.Now, "apply monthly interest");
    18. }
    19. }
    20. }

    2.3.2 GiftCardAccount 

    1. using Classes;
    2. //每月最后一天,可以充值一次指定的金额
    3. public class GiftCardAccount : BankAccount
    4. {
    5. private readonly decimal _monthlyDeposit = 0m;
    6. public GiftCardAccount(string name, decimal initialBalance, decimal monthlyDeposit = 0) : base(name, initialBalance)
    7. => _monthlyDeposit = monthlyDeposit;
    8. public override void PerformMonthEndTransactions()
    9. {
    10. if (_monthlyDeposit != 0)
    11. {
    12. MakeDeposit(_monthlyDeposit, DateTime.Now, "Add monthly deposit");
    13. }
    14. }
    15. }

    2.3.3 LineOfCreditAccount 

    1. using Classes;
    2. //信用帐户:
    3. //余额可以为负,但不能大于信用限额的绝对值。
    4. //如果月末余额不为 0,每个月都会产生利息。
    5. //将在超过信用限额的每次提款后收取费用
    6. public class LineOfCreditAccount : BankAccount
    7. {
    8. public LineOfCreditAccount(string name, decimal initialBalance) : base(name, initialBalance)
    9. {
    10. if (Balance < 0)
    11. {
    12. // Negate the balance to get a positive interest charge:
    13. decimal interest = -Balance * 0.07m;
    14. MakeWithdrawal(interest, DateTime.Now, "Charge monthly interest");
    15. }
    16. }
    17. public LineOfCreditAccount(string name, decimal initialBalance, decimal creditLimit) : base(name, initialBalance, -creditLimit)
    18. {
    19. }
    20. // 对超过限额的取款进行收费,而不是拒绝交易。
    21. protected override Transaction? CheckWithdrawalLimit(bool isOverdrawn) =>
    22. isOverdrawn
    23. ? new Transaction(-20, DateTime.Now, "Apply overdraft fee")
    24. : default;
    25. }

    2.4 主程序

    1. namespace Classes
    2. {
    3. class Program
    4. {
    5. static void Main(string[] args)
    6. {
    7. Console.WriteLine("Hello World!");
    8. var account = new BankAccount("", 1000);
    9. Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
    10. account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
    11. Console.WriteLine(account.Balance);
    12. account.MakeDeposit(100, DateTime.Now, "Friend paid me back");
    13. Console.WriteLine(account.Balance);
    14. Console.WriteLine(account.GetAccountHistory());
    15. var account1 = new BankAccount("lianhua", 1040);
    16. Console.WriteLine($"Account {account1.Number} was created for {account1.Owner} with {account1.Balance} initial balance.");
    17. Console.WriteLine(account1.GetAccountHistory());
    18. Console.WriteLine("_______________________________________");
    19. var giftCard = new GiftCardAccount("gift card", 100, 50);
    20. Console.WriteLine($"Account {giftCard.Number} was created for {giftCard.Owner} with {giftCard.Balance} initial balance.");
    21. giftCard.MakeWithdrawal(20, DateTime.Now, "get expensive coffee");
    22. giftCard.MakeWithdrawal(50, DateTime.Now, "buy groceries");
    23. giftCard.PerformMonthEndTransactions();
    24. // can make additional deposits:
    25. giftCard.MakeDeposit(27.50m, DateTime.Now, "add some additional spending money");
    26. Console.WriteLine(giftCard.GetAccountHistory());
    27. var savings = new InterestEarningAccount("savings account", 10000);
    28. Console.WriteLine($"Account {savings.Number} was created for {savings.Owner} with {savings.Balance} initial balance.");
    29. savings.MakeDeposit(750, DateTime.Now, "save some money");
    30. savings.MakeDeposit(1250, DateTime.Now, "Add more savings");
    31. savings.MakeWithdrawal(250, DateTime.Now, "Needed to pay monthly bills");
    32. savings.PerformMonthEndTransactions();
    33. Console.WriteLine(savings.GetAccountHistory());
    34. Console.WriteLine("____________________________");
    35. var lineOfCredit1 = new LineOfCreditAccount("line of credit", 0);
    36. Console.WriteLine($"Account {lineOfCredit1.Number} was created for {lineOfCredit1.Owner} with {lineOfCredit1.Balance} initial balance.");
    37. var lineOfCredit = new LineOfCreditAccount("line of credit", 0, 2000);
    38. Console.WriteLine($"Account {lineOfCredit.Number} was created for {lineOfCredit.Owner} with {lineOfCredit.Balance} initial balance.");
    39. // How much is too much to borrow?
    40. lineOfCredit.MakeWithdrawal(1000m, DateTime.Now, "Take out monthly advance");
    41. lineOfCredit.MakeDeposit(50m, DateTime.Now, "Pay back small amount");
    42. lineOfCredit.MakeWithdrawal(5000m, DateTime.Now, "Emergency funds for repairs");
    43. lineOfCredit.MakeDeposit(150m, DateTime.Now, "Partial restoration on repairs");
    44. lineOfCredit.PerformMonthEndTransactions();
    45. Console.WriteLine(lineOfCredit.GetAccountHistory());
    46. Test that the initial balances must be positive.
    47. //BankAccount invalidAccount;
    48. //try
    49. //{
    50. // invalidAccount = new BankAccount("invalid", -55);
    51. //}
    52. //catch (ArgumentOutOfRangeException e)
    53. //{
    54. // Console.WriteLine("Exception caught creating account with negative balance");
    55. // Console.WriteLine(e.ToString());
    56. // return;
    57. //}
    58. }
    59. }
    60. }

    三.结果

    1. Hello World!
    2. Account 1234567890 was created for with 1000 initial balance.
    3. 500
    4. 600
    5. Date Amount Balance Note
    6. 2022/11/11 1000 1000 Initial balance
    7. 2022/11/11 -500 500 Rent payment
    8. 2022/11/11 100 600 Friend paid me back
    9. Account 1234567891 was created for lianhua with 1040 initial balance.
    10. Date Amount Balance Note
    11. 2022/11/11 1040 1040 Initial balance
    12. _______________________________________
    13. Account 1234567892 was created for gift card with 100 initial balance.
    14. Date Amount Balance Note
    15. 2022/11/11 100 100 Initial balance
    16. 2022/11/11 -20 80 get expensive coffee
    17. 2022/11/11 -50 30 buy groceries
    18. 2022/11/11 50 80 Add monthly deposit
    19. 2022/11/11 27.50 107.50 add some additional spending money
    20. Account 1234567893 was created for savings account with 10000 initial balance.
    21. Date Amount Balance Note
    22. 2022/11/11 10000 10000 Initial balance
    23. 2022/11/11 750 10750 save some money
    24. 2022/11/11 1250 12000 Add more savings
    25. 2022/11/11 -250 11750 Needed to pay monthly bills
    26. 2022/11/11 587.50 12337.50 apply monthly interest
    27. ____________________________
    28. Account 1234567894 was created for line of credit with 0 initial balance.
    29. Account 1234567895 was created for line of credit with 0 initial balance.
    30. Date Amount Balance Note
    31. 2022/11/11 -1000 -1000 Take out monthly advance
    32. 2022/11/11 50 -950 Pay back small amount
    33. 2022/11/11 -5000 -5950 Emergency funds for repairs
    34. 2022/11/11 -20 -5970 Apply overdraft fee
    35. 2022/11/11 150 -5820 Partial restoration on repairs
    36. C:\...\net6.0\PracticeBasic.exe (process 9104) exited with code 0.
    37. Press any key to close this window . . .

  • 相关阅读:
    立创 EDA #学习笔记10# | 常用连接器元器件识别 和 无源蜂鸣器驱动电路
    股票量化择时策略(1)
    LLM - 大语言模型 基于人类反馈的强化学习(RLHF)
    day1_night-Python初识
    神经网络与深度学习(二):前馈神经网络
    党务管理系统搭建,答题获积分,学习有好礼
    React之使用脚手架启动页面
    【算法 - 动态规划】找零钱问题Ⅰ
    从负载均衡到路由,微服务应用现场一键到位
    Spring Cloud---使用gateway实现路由转发和负责均衡
  • 原文地址:https://blog.csdn.net/hellolianhua/article/details/127807666