> 字典 - 字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素,字典也称为映射或散列表。 - 字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List类,但没有在内存中移动后续元素的性能开销。 **键的类型** - 用作字典中的键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法。 - GetHashCode()方法的实现代码必须满足如下要求: - 相同的对象应总是返回相同的值。 - 不同的对象可以返回相同的值。 - 它不能抛出异常。 - 它应至少使用一个实例字段。 - 散列代码最好在对象的生存期中不发生变化。 - 它应执行的比较快,计算的开销不大 - 散列代码值应平均分布在int可以存储的整个数字范围上。 > 字典示例 - 字典示例程序建立一个员工字典。该字典用EmployeeId对象来索引,储存在字典中的每个数据项都是一个Employee对象,该对象存储员工的详细数据。 ``` public class EmployeeIdException:Exception { public EmployeeIdException(string message):base(message){} } public truct EmployeeId:IEquatable { private readonly char _prefix; private readonly int _number; public EmployeeId(string id) { Contract.Requires(id!=null); _prefix=(id.ToUpper())[0]; int numLength=id.Length-1; try { _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)*0x15051505; 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); } ``` - 由IEquatable接口定义的Equals()方法比较两个EmployeeId对象的值,如果这两个值相同,它就返回true。除了实现IEquatable接口中的Equals()方法之外,还可以重写Object类中的Equals()方法。 - Employee类是一个简单的实体类,该实体类包含员工的姓名、薪水和ID。构造函数初始化所有值,ToString()方法返回一个实例的字符串表示。ToString()方法的实现代码使用格式化字符串创建字符串表示,以提高性能 ``` public class Employee { private string _name; private 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}"; } ``` - 示例应用程序的Main()方法中,创建一个新的Dictionary实例,其中键是EmployeeId类型,值是Employee类型。构造函数指定31个元素的容量。注意容量一般是素数。但如果指定了一个不是素数的值,也不需要担心。Dictionary类会使用传递给构造函数的整数后面紧接着的一个素数来指定容量。创建员工对象和ID后,就使用新的字典初始化语法把它们添加到新建的字典中 ``` public static void Main() { var employees=new Dictionary(31); var idTony =new EmployeeId("c3755"); var tony =new Employee(idTony,"Tony Stewart",379025.00m); var idCarl=new EmployeeId("F3547"); var carl=new Employee(idCarl,"Carl Edwards",403466.00m); var idKevin=new EmployeeId("c3386"); var kevin=new Employee(idKevin,"Kevin Harwick",415261.00m); var idMatt=new EmployeeID("F3323"); var matt=new Employee(idMatt,"Matt Kenseth",1589390.00m); var idBrad=new EmployeeId("D3234"); var brad=new Employee(idBrad,"Brad Keselowski",322295.00m); var employees=new Dictionary(31) { [idTony]=tony, [idCarl]=carl, [idKevin]=kevin, [idMatt]=matt, [idBrad]=brad }; foreach(var employee inemployee.Values) { WriteLine(employee); } } ``` ``` while (true) { Write("Enter employee id(X to exit)"); var userInput=ReadLine(); userInput=userInput.ToUpper(); if(userInput == "X") break; EmployeeId id; try { id=new EmployeeId(userInput); Employee employee; if(!employee.TryGetValue(id,out employee)) { WriteLine($"Employee with id{id} does not exist"); } else { WriteLine(employee); } } catch(EmployeeIdException ex) { WriteLine(ex.Message); } } ```