C#银行系统SortedSet未按余额降序排列及构造函数添加实例疑问
问题解决与优化方案
一、排序异常的原因及修复
你的代码中SortedSet未按余额降序输出,核心问题有两个:
1. 比较逻辑方向错误
当前CompareTo方法使用return _balance.CompareTo(other._balance),这是升序逻辑(余额小的对象会排在前面)。要实现降序,必须反转比较方向:
public int CompareTo(Bank? other) { if (other == null) return 1; // 空对象后置 // 余额相同则按ID升序保证唯一性,避免SortedSet去重错误 if (_balance == other._balance) return _id.CompareTo(other._id); // 反转比较方向实现余额降序 return other._balance.CompareTo(_balance); }
2. 构造函数添加时机错误
带余额参数的构造函数先调用无参构造(此时_balance为默认值0),将未完成初始化的对象添加到SortedSet,之后才设置实际余额。这导致集合排序基于初始的0值而非最终余额。修复方式是先初始化余额,再添加到集合:
public Bank() { _id = numOfAccounts; numOfAccounts++; // 移除构造函数内的_banks.Add(this) } public Bank(double balance) : this() { _balance = balance; _banks.Add(this); // 先设置余额再加入集合 }
另外,withdrawal方法修改余额后未更新集合排序,需要补充Remove/Add操作:
public bool withdrawal(double balance) { if(this._balance >= balance) { _banks.Remove(this); this._balance -= balance; _banks.Add(this); return true; } return false; }
二、构造函数中添加实例的合理性分析
这种做法存在明显缺陷:
- 强耦合:创建
Bank对象就必须加入静态集合,无法灵活创建独立的账户实例(比如测试用例)。 - 初始化风险:构造函数执行时对象可能未完全初始化(如之前的余额设置滞后问题),导致集合中存储的对象状态不一致。
- 扩展性差:后续如果需要多个账户集合(比如按不同维度分类),现有逻辑无法支持。
三、更优实现方案
1. 分离集合管理与账户逻辑
将静态集合的管理从Bank类中剥离,创建单独的BankManager类负责维护账户集合,让Bank类专注于账户自身逻辑:
public class BankManager { private readonly SortedSet<Bank> _accounts = new SortedSet<Bank>(new BankComperatorByBalance()); public void AddAccount(Bank account) { _accounts.Add(account); } public bool RemoveAccount(Bank account) { return _accounts.Remove(account); } public IEnumerable<Bank> GetAccountsSortedByBalanceDesc() { return _accounts; } } public class Bank : IComparable<Bank> { private static int numOfAccounts = 0; public int Id { get; } public double Balance { get; private set; } public Bank(double balance) { Id = numOfAccounts++; Balance = balance; } public void Deposit(double amount) { Balance += amount; } public bool Withdraw(double amount) { if (Balance >= amount) { Balance -= amount; return true; } return false; } public bool Transfer(Bank receiver, double amount) { if (Withdraw(amount)) { receiver.Deposit(amount); return true; } return false; } public override string ToString() { return $"id: {Id}\nBalance: {Balance}"; } public int CompareTo(Bank? other) { if (other == null) return 1; if (Balance == other.Balance) return Id.CompareTo(other.Id); return other.Balance.CompareTo(Balance); } public override bool Equals(object? obj) { return obj is Bank bank && Id == bank.Id; } public override int GetHashCode() { return Id.GetHashCode(); } } class BankComperatorByBalance : Comparer<Bank> { public override int Compare(Bank? x, Bank? y) { if (x == null) return 1; if (y == null) return -1; return x.CompareTo(y); } }
2. 使用静态创建方法(简化版)
如果不想新增类,可以用静态方法封装对象创建与集合添加逻辑,同时将构造函数设为私有避免直接实例化:
public class Bank : IComparable<Bank> { private static int numOfAccounts = 0; private readonly int _id; private double _balance; private static readonly SortedSet<Bank> _banks = new SortedSet<Bank>(new BankComperatorByBalance()); // 私有构造函数,强制通过静态方法创建 private Bank(double balance) { _id = numOfAccounts++; _balance = balance; } public static Bank CreateAccount(double balance) { var account = new Bank(balance); _banks.Add(account); return account; } // 存款、取款等方法按修复后的逻辑实现 }
3. 修正Transfer方法逻辑
原代码中transfer方法逻辑错误(转出方误用了存款操作),正确实现如下:
public bool Transfer(Bank receiver, double balance) { if (this._balance >= balance) { this.withdrawal(balance); receiver.deposit(balance); return true; } return false; }
内容的提问来源于stack exchange,提问作者Adam Hafchadi
相关产品推荐
相关产品推荐

