因为不同的键,可能返回相同的散列代码值,所以需要用Equals()方法来比较键,
A.Equals(B)
。
必须始终确保如下条件成立: 如果
A.Equals(B)
为true, 那么
A.GetHashCode()和B.GetHashCode()
总是返回相同的散列代码值。这个条件成立很重要,如果用作键的类型不满足此条件,字典就不能正常工作,会发生有趣的事情,例如放进字典后就再也检索不到它,或者检索得到错误的项。
System.Object
作为字典的键
Equals(),比较引用
GetHashCode(), 返回一个基于对象地址的散列代码值
把
类实例
作为key,而放入字典的value时,
类实例的引用
和value建立了一一对应的关系,
若想检索value
, 就必须保存着类实例的引用,
这不太方便
!
要想方便
,这个类需要重写
Equals()
和
GetHashCode()
System.String
作为字典的键
实现了
IEquatable
接口,
Equals()
比较值
GetHashCode()
,返回一个基于字符串值的散列代码值
System.String
作为字典的键,很方便
Int32
作为字典的键
实现了
IEquatable
接口
GetHashCode()
把
Int32
作为键,其
散列代码值
可能
没有平均分布
在int.MinValue和int.MaxValue之间,因此,不能获得
最佳性能
。
因此,Int32不太适合作为键
如果
键类型
没有实现
IEquatable
接口,也没有重写
GetHashCode()
方法
Dictionary<TKey, TValue>
构造函数的重载版本,接收一个
IEqualityComparer<T>
IEqualityComparer<T>
定义了
GetHashCode()
和
Equals()
public class Employee
private readonly string _name;
private readonly decimal _salary;
private readonly EmployeeId _id;
public Employee(EmployeeId id, string name, decimal salary)
_id = id;
_name = name;
_salary = salary;
public override string ToString() => $"{_id.ToString()}: {_name, -20} {_salary :C}";
public class EmployeeIdException : Exception
public EmployeeIdException(string message) : base(message) { }
public struct EmployeeId : IEquatable<EmployeeId>
private readonly char _prefix;
private readonly int _number;
public EmployeeId(string id)
if (id == null) throw new ArgumentNullException(nameof(id));
_prefix = (id.ToUpper())[0];
int numLength = id.Length - 1;
_number = int.Parse(id.Substring(1, numLength > 6 ? 6 : numLength));
catch (FormatException)
throw new EmployeeIdException("Invalid EmployeeId format");
public override string ToString() => _prefix.ToString() + $"{_number,6:000000}";
public override int GetHashCode() => (_number ^ _number << 16) * 0x1505_1505;
public bool Equals(EmployeeId other) => _prefix == other._prefix && _number == other._number;
public override bool Equals(object obj) => Equals((EmployeeId)obj);
public static bool operator ==(EmployeeId left, EmployeeId right) => left.Equals(right);
public static bool operator !=(EmployeeId left, EmployeeId right) => !(left == right);
class Program
static void Main()
var idJimmie = new EmployeeId("C48");
var jimmie = new Employee(idJimmie, "Jimmie Johnson", 150926.00m);
var idJoey = new EmployeeId("F22");
var joey = new Employee(idJoey, "Joey Logano", 45125.00m);
var idKyle = new EmployeeId("T18");
var kyle = new Employee(idKyle, "Kyle Bush", 78728.00m);
var idCarl = new EmployeeId("T19");
var carl = new Employee(idCarl, "Carl Edwards", 80473.00m);
var idMatt = new EmployeeId("T20");
var matt = new Employee(idMatt, "Matt Kenseth", 113970.00m);
var employees = new Dictionary<EmployeeId, Employee>(31)
[idJimmie] = jimmie,
[idJoey] = joey,
[idKyle] = kyle,
[idCarl] = carl,
[idMatt] = matt
foreach (var employee in employees.Values)
Console.WriteLine(employee);
while (true)
Console.Write("Enter employee id (X to exit)> ");
var userInput = Console.ReadLine();
userInput = userInput.ToUpper();
if (userInput == "X") break;
EmployeeId id;
id = new EmployeeId(userInput);
if (!employees.TryGetValue(id, out Employee employee))
Console.WriteLine($"Employee with id {id} does not exist");
Console.WriteLine(employee);
catch (EmployeeIdException ex)
Console.WriteLine(ex.Message);
输出:(存入字典的数据项都能用键给检索出来)
C000048: Jimmie Johnson ¥150,926.00
F000022: Joey Logano ¥45,125.00
T000018: Kyle Bush ¥78,728.00
T000019: Carl Edwards ¥80,473.00
T000020: Matt Kenseth ¥113,970.00
Enter employee id (X to exit)> T19
T000019: Carl Edwards ¥80,473.00
Enter employee id (X to exit)> 148
Employee with id 1000048 does not exist
Enter employee id (X to exit)> T48
Employee with id T000048 does not exist
Enter employee id (X to exit)> C48
C000048: Jimmie Johnson ¥150,926.00
Enter employee id (X to exit)> F22
F000022: Joey Logano ¥45,125.00
Enter employee id (X to exit)>
复制代码