var c1 = new Customer("Acme Products");
map.Add(c1, orders);
// 稍後修改名稱
c1.Name = "Acme Software"; // GetHashCode() 改變!
// 現在找不到 c1 了!
// c1 存放在 "Acme Products" 桶,但現在雜湊值對應 "Acme Software" 桶
var lost = map[c1]; // null 或 KeyNotFound
裝箱/拆箱會複製資料。加入集合後修改欄位,集合內的複製品不受影響,但邏輯上仍錯誤。
public class Customer
{
private readonly string _name; // 唯讀!
public string Name => _name;
public Customer(string name) => _name = name;
// 修改名稱 → 回傳新實例
public Customer WithName(string newName) => new Customer(newName);
public override int GetHashCode() => _name.GetHashCode();
}
var c1 = new Customer("Acme Products");
map.Add(c1, orders);
var c2 = c1.WithName("Acme Software"); // 新實例,新雜湊值
var o = map[c1]; // 仍能找到原本
map.Remove(c1);
map.Add(c2, o); // 以新鍵重新加入
public override int GetHashCode()
{
// 方案 1:單一不可變欄位
return _keyField.GetHashCode();
// 方案 2:多欄位 XOR(經典演算法)
unchecked
{
int hash = 17;
hash = hash * 23 + _field1.GetHashCode();
hash = hash * 23 + _field2.GetHashCode();
return hash;
}
// 方案 3:Tuple 組合 (C# 7+)
return (_field1, _field2, _field3).GetHashCode();
}
a.Equals(b) → a.GetHashCode() == b.GetHashCode()Object.GetHashCode():物件 ID(正確但分布差,效能低)ValueType.GetHashCode():第一個欄位雜湊碼(僅當第一欄位不可變且分布佳時正確)只有不可變型別才適合作雜湊鍵。若型別可變,不要覆寫 GetHashCode(),讓預設參考相等語意生效(或明確文件化不支援雜湊集合)。