|
@@ -0,0 +1,142 @@
|
|
1
|
+> 字典
|
|
2
|
+- 字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素,字典也称为映射或散列表。
|
|
3
|
+- 字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List<T>类,但没有在内存中移动后续元素的性能开销。
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+**键的类型**
|
|
7
|
+
|
|
8
|
+- 用作字典中的键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法。
|
|
9
|
+- GetHashCode()方法的实现代码必须满足如下要求:
|
|
10
|
+ - 相同的对象应总是返回相同的值。
|
|
11
|
+ - 不同的对象可以返回相同的值。
|
|
12
|
+ - 它不能抛出异常。
|
|
13
|
+ - 它应至少使用一个实例字段。
|
|
14
|
+ - 散列代码最好在对象的生存期中不发生变化。
|
|
15
|
+ - 它应执行的比较快,计算的开销不大
|
|
16
|
+ - 散列代码值应平均分布在int可以存储的整个数字范围上。
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+> 字典示例
|
|
20
|
+
|
|
21
|
+- 字典示例程序建立一个员工字典。该字典用EmployeeId对象来索引,储存在字典中的每个数据项都是一个Employee对象,该对象存储员工的详细数据。
|
|
22
|
+```
|
|
23
|
+public class EmployeeIdException:Exception
|
|
24
|
+{
|
|
25
|
+ public EmployeeIdException(string message):base(message){}
|
|
26
|
+}
|
|
27
|
+public truct EmployeeId:IEquatable<EmployeeId>
|
|
28
|
+{
|
|
29
|
+ private readonly char _prefix;
|
|
30
|
+ private readonly int _number;
|
|
31
|
+
|
|
32
|
+ public EmployeeId(string id)
|
|
33
|
+ {
|
|
34
|
+ Contract.Requires<ArgumentNullException>(id!=null);
|
|
35
|
+
|
|
36
|
+ _prefix=(id.ToUpper())[0];
|
|
37
|
+ int numLength=id.Length-1;
|
|
38
|
+ try
|
|
39
|
+ {
|
|
40
|
+ _number=int.Parse(id.Substring(1,numLength>6?6:numLength));
|
|
41
|
+ }
|
|
42
|
+ catch (FormatException)
|
|
43
|
+ {
|
|
44
|
+ throw new EmployeeIdException("Invalid EmployeeId format");
|
|
45
|
+ }
|
|
46
|
+ }
|
|
47
|
+ public override string ToString()=>_prefix.ToString()+$"{number,6:000000}";
|
|
48
|
+ public override int GetHashCode()=>(number^number<<16)*0x15051505;
|
|
49
|
+ public bool Equals(EmployeeId other)=>(prefix==other?.prefix && number == other?.number);
|
|
50
|
+ public override bool Equals(object obj)=>Equals((EmployeeId)obj);
|
|
51
|
+
|
|
52
|
+ public static bool operator ==(EmployeeId left,EmployeeId right)=>left.Equals(right);
|
|
53
|
+
|
|
54
|
+ public static bool operator !=(EmployeeId left,EmployeeId right)=>!(left==right);
|
|
55
|
+
|
|
56
|
+}
|
|
57
|
+```
|
|
58
|
+- 由IEquatable<T>接口定义的Equals()方法比较两个EmployeeId对象的值,如果这两个值相同,它就返回true。除了实现IEquatable<T>接口中的Equals()方法之外,还可以重写Object类中的Equals()方法。
|
|
59
|
+
|
|
60
|
+- Employee类是一个简单的实体类,该实体类包含员工的姓名、薪水和ID。构造函数初始化所有值,ToString()方法返回一个实例的字符串表示。ToString()方法的实现代码使用格式化字符串创建字符串表示,以提高性能
|
|
61
|
+
|
|
62
|
+```
|
|
63
|
+public class Employee
|
|
64
|
+{
|
|
65
|
+ private string _name;
|
|
66
|
+ private decimal _salary;
|
|
67
|
+ private readonly EmployeeId _id;
|
|
68
|
+
|
|
69
|
+ public Employee (EmployeeId id,string name,decimal salary)
|
|
70
|
+ {
|
|
71
|
+ _id=id;
|
|
72
|
+ _name=name;
|
|
73
|
+ _salary=salary;
|
|
74
|
+ }
|
|
75
|
+ public override string ToString()=>$"{id.ToString()}:{name,-20} {salary:C}";
|
|
76
|
+}
|
|
77
|
+```
|
|
78
|
+- 示例应用程序的Main()方法中,创建一个新的Dictionary<TKey,TValue>实例,其中键是EmployeeId类型,值是Employee类型。构造函数指定31个元素的容量。注意容量一般是素数。但如果指定了一个不是素数的值,也不需要担心。Dictionary<TKey,Tvalue>类会使用传递给构造函数的整数后面紧接着的一个素数来指定容量。创建员工对象和ID后,就使用新的字典初始化语法把它们添加到新建的字典中
|
|
79
|
+
|
|
80
|
+```
|
|
81
|
+public static void Main()
|
|
82
|
+{
|
|
83
|
+ var employees=new Dictionary<EmployeeId,Employee>(31);
|
|
84
|
+ var idTony =new EmployeeId("c3755");
|
|
85
|
+ var tony =new Employee(idTony,"Tony Stewart",379025.00m);
|
|
86
|
+
|
|
87
|
+ var idCarl=new EmployeeId("F3547");
|
|
88
|
+ var carl=new Employee(idCarl,"Carl Edwards",403466.00m);
|
|
89
|
+
|
|
90
|
+ var idKevin=new EmployeeId("c3386");
|
|
91
|
+ var kevin=new Employee(idKevin,"Kevin Harwick",415261.00m);
|
|
92
|
+
|
|
93
|
+ var idMatt=new EmployeeID("F3323");
|
|
94
|
+ var matt=new Employee(idMatt,"Matt Kenseth",1589390.00m);
|
|
95
|
+
|
|
96
|
+ var idBrad=new EmployeeId("D3234");
|
|
97
|
+ var brad=new Employee(idBrad,"Brad Keselowski",322295.00m);
|
|
98
|
+
|
|
99
|
+ var employees=new Dictionary<EmployeeId,Employee>(31)
|
|
100
|
+ {
|
|
101
|
+ [idTony]=tony,
|
|
102
|
+ [idCarl]=carl,
|
|
103
|
+ [idKevin]=kevin,
|
|
104
|
+ [idMatt]=matt,
|
|
105
|
+ [idBrad]=brad
|
|
106
|
+ };
|
|
107
|
+ foreach(var employee inemployee.Values)
|
|
108
|
+ {
|
|
109
|
+ WriteLine(employee);
|
|
110
|
+ }
|
|
111
|
+}
|
|
112
|
+```
|
|
113
|
+```
|
|
114
|
+while (true)
|
|
115
|
+{
|
|
116
|
+ Write("Enter employee id(X to exit)");
|
|
117
|
+ var userInput=ReadLine();
|
|
118
|
+ userInput=userInput.ToUpper();
|
|
119
|
+ if(userInput == "X") break;
|
|
120
|
+
|
|
121
|
+ EmployeeId id;
|
|
122
|
+ try
|
|
123
|
+ {
|
|
124
|
+ id=new EmployeeId(userInput);
|
|
125
|
+
|
|
126
|
+ Employee employee;
|
|
127
|
+ if(!employee.TryGetValue(id,out employee))
|
|
128
|
+ {
|
|
129
|
+ WriteLine($"Employee with id{id} does not exist");
|
|
130
|
+
|
|
131
|
+ }
|
|
132
|
+ else
|
|
133
|
+ {
|
|
134
|
+ WriteLine(employee);
|
|
135
|
+ }
|
|
136
|
+ }
|
|
137
|
+ catch(EmployeeIdException ex)
|
|
138
|
+ {
|
|
139
|
+ WriteLine(ex.Message);
|
|
140
|
+ }
|
|
141
|
+}
|
|
142
|
+```
|