當自定義類需要實現索引時,可以在類中實現索引器。
用Table作為例子,Table由多個Row組成,Row由多個Cell組成,
我們需要實現自定義的table[0],row[0]
索引器定義格式為
[修飾符] 數據類型 this[索引類型 index]
以下是代碼
1 /// <summary> 2 /// 單元格 3 /// </summary> 4 public class Cell 5 { 6 /// <summary> 7 /// Value 8 /// </summary> 9 public object Value { get; set; } 10 /// <summary> 11 /// StringValue 12 /// </summary> 13 public string StringValue { get; set; } 14 }View Code
1 /// <summary> 2 /// 行 3 /// </summary> 4 public class Row 5 { 6 /// <summary> 7 /// 獲取Row中的Cell數 8 /// </summary> 9 public int Length { get; private set; } 10 11 /// <summary> 12 /// 索引 13 /// </summary> 14 public Cell this[int column] 15 { 16 get 17 { 18 return this[column]; 19 } 20 } 21 /// <summary> 22 /// 行 23 /// </summary> 24 /// <param name="values"></param> 25 public Row(object[] values) 26 { 27 this.Length = values.Length; 28 for (int i = 0; i < this.Length; i++) 29 { 30 this[i].Value = values[i]; 31 this[i].StringValue = Convert.ToString(values[i]); 32 } 33 } 34 /// <summary> 35 /// 行 36 /// </summary> 37 /// <param name="values"></param> 38 public Row(string[] values) 39 { 40 this.Length = values.Length; 41 for (int i = 0; i < this.Length; i++) 42 { 43 this[i].Value = values[i]; 44 this[i].StringValue = values[i]; 45 } 46 } 47 /// <summary> 48 /// 行 49 /// </summary> 50 /// <param name="values"></param> 51 public Row(int[] values) 52 { 53 this.Length = values.Length; 54 for (int i = 0; i < this.Length; i++) 55 { 56 this[i].Value = values[i]; 57 this[i].StringValue = values[i].ToString(); 58 } 59 } 60 }View Code
這時候,Row就可以有自己的索引了,調用如下
1 public class Test 2 { 3 public Test() 4 { 5 Row row = new Row(new string[] { "姓名", "性別", "工號" }); 6 if (row.Length > 2) 7 { 8 row[2].StringValue = "學號"; 9 } 10 } 11 }View Code
但是,Row雖然作為一個Cell的集合,卻不能使用foreach進行遍歷。這時候我們需要讓Row繼承IEnumerable接口,並且實現IEnumerable接口的GetEnumerator()方法,
在public class Row : IEnumerable { }中添加如下代碼:
1 /// <summary> 2 /// 實現GetEnumerator()方法 3 /// </summary> 4 /// <returns></returns> 5 public IEnumerator GetEnumerator() 6 { 7 for (int i = 0; i < this.Length; i++) 8 { 9 yield return this[i]; 10 } 11 }View Code
這樣,在調用的時候就能使用foreach遍歷了。
Table和Row的關系同理。
同樣,我們還可以繼承ICollection<T>, IEnumerable<T>, IList<T>等接口,實現相關接口的方法,就可以打造屬於自己的集合了。
一個完整的Demo如下:
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Text; 6 7 namespace MyCollection 8 { 9 /// <summary> 10 /// 表示 Cell 集合 11 /// </summary> 12 [DebuggerDisplay("Count = {Count}")] 13 [Serializable] 14 public class MyCollection : IEnumerable, IEnumerable<Cell>, ICollection<Cell>, IList<Cell> 15 { 16 #region 字段 17 18 /// <summary> 19 /// 表示空的 Row 圖層的數組。 20 /// </summary> 21 private readonly static Row[] emptyArray = null; 22 23 /// <summary> 24 /// 存儲 Row 圖層的數組。 25 /// </summary> 26 private Row[] items = null; 27 28 /// <summary> 29 /// 當前 Row 圖層的集合的元素數。 30 /// </summary> 31 private int count = 0; 32 33 #endregion 34 35 #region 屬性 36 37 /// <summary> 38 /// 獲取或設置該 Row 的元素總數。 39 /// </summary> 40 /// <exception cref="System.ArgumentOutOfRangeException">MyCollection.Capacity 設置為小於 MyCollection.Count 的值。</exception> 41 private int Capacity 42 { 43 get 44 { 45 return this.items.Length; 46 } 47 set 48 { 49 if (value != this.items.Length) 50 { 51 if (value < this.count) 52 { 53 throw new ArgumentOutOfRangeException("Capacity", "MyCollection.Capacity 設置為小於 MyCollection.Count 的值。"); 54 } 55 if (value > 0) 56 { 57 Row[] destArray = new Row[value]; 58 if (this.count > 0) 59 { 60 Array.Copy(this.items, 0, destArray, 0, this.count); 61 } 62 this.items = destArray; 63 } 64 else 65 { 66 this.items = emptyArray; 67 } 68 } 69 } 70 } 71 72 #endregion 73 74 #region 構造函數 75 /// <summary> 76 /// 對 LayerCollection 類進行初始化。 77 /// </summary> 78 static MyCollection() 79 { 80 emptyArray = new Row[0]; 81 } 82 83 /// <summary> 84 /// 初始化 HuaXing.ExamOperation.SimulateFlash.LayerCollection 類的新實例。<para/> 85 /// 表示 Layer 圖層的集合。 86 /// </summary> 87 public MyCollection() 88 { 89 this.items = emptyArray; 90 } 91 #endregion 92 93 #region IList<Row> 成員 94 95 #region IndexOf 96 97 /// <summary> 98 /// 搜索指定的 Row 對象,並返回整個 MyCollection 中第一個匹配項的從零開始的索引。 99 /// </summary> 100 /// <param name="item">要在 MyCollection 中定位的 Row 對象。</param> 101 /// <returns>如果在 MyCollection 中找到 item 的第一個匹配項,則為該項的從零開始的索引;否則為-1。</returns> 102 public int IndexOf(Row item) 103 { 104 return Array.IndexOf<Row>(this.items, item, 0, this.count); 105 } 106 107 /// <summary> 108 /// 搜索指定的 Row 對象,並返回整個 MyCollection 中從指定索引到最後一個元素的元素范圍內第一個匹配項的從零開始的索引。 109 /// </summary> 110 /// <param name="item">要在 MyCollection 中定位的 Row 對象。</param> 111 /// <param name="index">從零開始的搜索的起始索引。</param> 112 /// <returns>如果在 MyCollection 中從 index 到最後一個元素的元素范圍內找到 item 的第一個匹配項,則為該項的從零開始的索引;否則為-1。</returns> 113 /// <exception cref="System.ArgumentOutOfRangeException">index 不在 MyCollection 的有效索引范圍內。</exception> 114 public int IndexOf(Row item, int index) 115 { 116 if (index < 0 || index > this.count) 117 { 118 throw new ArgumentOutOfRangeException("index", "index 不在 MyCollection 的有效索引范圍內。"); 119 } 120 return Array.IndexOf<Row>(this.items, item, index, this.count - index); 121 } 122 123 /// <summary> 124 /// 搜索指定的 Row 對象,並返回整個 MyCollection 中從指定的索引開始並包含指定的元素數的元素范圍內第一個匹配項的從零開始的索引。 125 /// </summary> 126 /// <param name="item">要在 MyCollection 中定位的 Row 對象。</param> 127 /// <param name="index">從零開始的搜索的起始索引。</param> 128 /// <param name="count">要搜索的部分中的元素數。</param> 129 /// <returns>如果在 MyCollection 中從 index 開始並包含 count 個元素的元素范圍內找到 item 的第一個匹配項,則為該項的從零開始的索引;否則為-1。</returns> 130 /// <exception cref="System.ArgumentOutOfRangeException">index 不在 MyCollection 的有效索引范圍內 或 count 小於 0 或 index 和 count 未指定 MyCollection 中的有效部分。</exception> 131 public int IndexOf(Row item, int index, int count) 132 { 133 if (index < 0 || index > this.count) 134 { 135 throw new ArgumentOutOfRangeException("index", "index 不在 MyCollection 的有效索引范圍內。"); 136 } 137 if ((count < 0) || (index > (this.count - count))) 138 { 139 throw new ArgumentOutOfRangeException("count", "count 小於 0 或 index 和 count 未指定 MyCollection 中的有效部分。"); 140 } 141 return Array.IndexOf<Row>(this.items, item, index, count); 142 } 143 144 #endregion 145 146 #region Insert 147 148 /// <summary> 149 /// 將 Row 對象插入 MyCollection 的指定索引處。 150 /// </summary> 151 /// <param name="index">從零開始的索引,應在該位置插入 item。</param> 152 /// <param name="item">要插入的 Row 對象。</param> 153 /// <exception cref="System.ArgumentOutOfRangeException">index 小於 0 或 index 大於 MyCollection.Count。</exception> 154 public void Insert(int index, Row item) 155 { 156 if (index < 0 || index > this.count) 157 { 158 throw new ArgumentOutOfRangeException("index", "index 小於 0 或 index 大於 MyCollection.Count。"); 159 } 160 if (this.count == this.items.Length) 161 { 162 this.EnsureCapacity(this.count + 1); 163 } 164 if (index < this.count) 165 { 166 Array.Copy(this.items, index, this.items, index + 1, this.count - index); 167 } 168 this.items[index] = item; 169 this.count++; 170 } 171 172 #endregion 173 174 #region RemoveAt 175 176 /// <summary> 177 /// 移除 MyCollection 的指定索引處的 Row 對象。 178 /// </summary> 179 /// <param name="index">要移除的 Row 對象的從零開始的索引。</param> 180 /// <exception cref="System.ArgumentOutOfRangeException">index 小於 0 或 index 等於或大於 MyCollection.Count。</exception> 181 public void RemoveAt(int index) 182 { 183 if (index < 0 || index >= this.count) 184 { 185 throw new ArgumentOutOfRangeException("index", "index 小於 0 或 index 等於或大於 MyCollection.Count。"); 186 } 187 this.count--; 188 if (index < this.count) 189 { 190 Array.Copy(this.items, index + 1, this.items, index, this.count - index); 191 } 192 this.items[this.count] = default(Row); 193 } 194 195 #endregion 196 197 #region Item[Int32] 198 199 /// <summary> 200 /// 獲取或設置指定索引處的 Row 對象。 201 /// </summary> 202 /// <param name="index">要獲取或設置的 Row 對象從零開始的索引。</param> 203 /// <returns>指定索引處的 Row 對象。</returns> 204 /// <exception cref="System.ArgumentOutOfRangeException">index 小於 0 或 index 等於或大於 MyCollection.Count。</exception> 205 public Row this[int index] 206 { 207 get 208 { 209 if (index < 0 && index >= this.count) 210 { 211 throw new ArgumentOutOfRangeException("index", "index 小於 0 或 index 等於或大於 MyCollection.Count。"); 212 } 213 else 214 { 215 return this.items[index]; 216 } 217 } 218 set 219 { 220 if (index < 0 && index >= this.count) 221 { 222 throw new ArgumentOutOfRangeException("index", "index 小於 0 或 index 等於或大於 MyCollection.Count。"); 223 } 224 else 225 { 226 this.items[index] = value; 227 } 228 } 229 } 230 231 #endregion 232 233 #endregion 234 235 #region ICollection<Row> 成員 236 237 #region Add 238 239 /// <summary> 240 /// 將 Row 對象,添加到 MyCollection 的結尾處。 241 /// </summary> 242 /// <param name="item">要添加到 MyCollection 的末尾處的 Row 對象。</param> 243 public void Add(Row item) 244 { 245 if (this.count == this.items.Length) 246 { 247 this.EnsureCapacity(this.count + 1); 248 } 249 this.items[this.count++] = item; 250 } 251 252 #endregion 253 254 #region Clear 255 256 /// <summary> 257 /// 從 MyCollection 集合中移除所有元素。 258 /// </summary> 259 public void Clear() 260 { 261 if (this.count > 0) 262 { 263 Array.Clear(this.items, 0, this.count); 264 this.count = 0; 265 } 266 } 267 268 #endregion 269 270 #region Contains 271 272 /// <summary> 273 /// 確定 MyCollection 集合中,是否包含特定值。 274 /// </summary> 275 /// <param name="value">要在 MyCollection 集合中查找的 Row。</param> 276 /// <returns>如果在 MyCollection 集合中找到 Row,則為true;否則為false。</returns> 277 public bool Contains(Row value) 278 { 279 if (value == null) 280 { 281 for (int j = 0; j < this.count; j++) 282 { 283 if (this.items[j] == null) 284 { 285 return true; 286 } 287 } 288 return false; 289 } 290 EqualityComparer<Row> comparer = EqualityComparer<Row>.Default; 291 for (int i = 0; i < this.count; i++) 292 { 293 if (comparer.Equals(this.items[i], value)) 294 { 295 return true; 296 } 297 } 298 return false; 299 } 300 301 #endregion 302 303 #region CopyTo 304 305 /// <summary> 306 /// 將整個 MyCollection 復制到一維數組中,從目標數組的開頭開始放置。 307 /// </summary> 308 /// <param name="array">作為從 MyCollection 復制的元素的目標位置的一維數組。</param> 309 /// <exception cref="System.ArgumentException">源 MyCollection 中的元素數大於目標 array 可包含的元素數。</exception> 310 /// <exception cref="System.ArgumentNullException">array 為 null。</exception> 311 public void CopyTo(Row[] array) 312 { 313 this.CopyTo(array, 0); 314 } 315 316 /// <summary> 317 /// 將整個 MyCollection 復制到一維數組中,從目標數組的指定索引位置開始放置。 318 /// </summary> 319 /// <param name="array">作為從 MyCollection 復制的元素的目標位置的一維數組。</param> 320 /// <param name="arrayIndex">array 中從零開始的索引,在此處開始復制。</param> 321 /// <exception cref="System.ArgumentException">arrayIndex 等於或大於 array 的長度 或 源 MyCollection 中的元素數目大於從 arrayIndex 到目標 array 末尾之間的可用空間。</exception> 322 /// <exception cref="System.ArgumentNullException">array 為 null。</exception> 323 /// <exception cref="System.ArgumentOutOfRangeException">arrayIndex 小於 0。</exception> 324 public void CopyTo(Row[] array, int arrayIndex) 325 { 326 Array.Copy(this.items, 0, array, arrayIndex, this.count); 327 } 328 329 /// <summary> 330 /// 將一定范圍的元素從 MyCollection 復制到一維數組中,從目標數組的指定索引位置開始放置。 331 /// </summary> 332 /// <param name="index">源 MyCollection 中復制開始位置的從零開始的索引。</param> 333 /// <param name="array">作為從 MyCollection 復制的元素的目標位置的一維數組。</param> 334 /// <param name="arrayIndex">array 中從零開始的索引,在此處開始復制。</param> 335 /// <param name="count">要復制的元素數。</param> 336 /// <exception cref="System.ArgumentException">index 等於或大於源 MyCollection 的 MyCollection.Count 或 arrayIndex 等於或大於 array 的長度 或 從 index 到源 MyCollection 的末尾的元素數大於從 arrayIndex 到目標 array 的末尾的可用空間。</exception> 337 /// <exception cref="System.ArgumentNullException">array 為 null。</exception> 338 /// <exception cref="System.ArgumentOutOfRangeException">index 小於 0 或 arrayIndex 小於 0 或 count 小於 0。</exception> 339 public void CopyTo(int index, Row[] array, int arrayIndex, int count) 340 { 341 if ((this.count - index) < count) 342 { 343 throw new ArgumentException("index 等於或大於源 MyCollection 的 MyCollection.Count 或 arrayIndex 等於或大於 array 的長度 或 從 index 到源 MyCollection 的末尾的元素數大於從 arrayIndex 到目標 array 的末尾的可用空間。", "index"); 344 } 345 Array.Copy(this.items, index, array, arrayIndex, count); 346 } 347 348 #endregion 349 350 #region Count 351 352 /// <summary> 353 /// 獲取當前 Row 集合的元素數。 354 /// </summary> 355 public int Count 356 { 357 get 358 { 359 return this.count; 360 } 361 } 362 363 #endregion 364 365 #region IsReadOnly 366 367 /// <summary> 368 /// 獲取一個值,該值指示 MyCollection 是否為只讀。 369 /// </summary> 370 bool ICollection<Row>.IsReadOnly 371 { 372 get 373 { 374 return false; 375 } 376 } 377 378 #endregion 379 380 #region Remove 381 382 /// <summary> 383 /// 從 MyCollection 中移除特定 Row 對象的第一個匹配項。 384 /// </summary> 385 /// <param name="item">要從 MyCollection 中移除的 Row 對象。</param> 386 /// <returns>如果成功移除 item,則為 true;否則為 false。如果在 MyCollection 中沒有找到 item,該方法也會返回 false。</returns> 387 public bool Remove(Row item) 388 { 389 int index = this.IndexOf(item); 390 if (index >= 0) 391 { 392 this.RemoveAt(index); 393 return true; 394 } 395 return false; 396 } 397 398 #endregion 399 400 #endregion 401 402 #region IEnumerable<Row> 成員 403 404 public IEnumerator<Row> GetEnumerator() 405 { 406 for (int index = 0; index < this.count; index++) 407 { 408 yield return this.items[index]; 409 } 410 } 411 412 #endregion 413 414 #region IEnumerable 成員 415 416 IEnumerator IEnumerable.GetEnumerator() 417 { 418 for (int index = 0; index < this.count; index++) 419 { 420 yield return this.items[index]; 421 } 422 } 423 424 #endregion 425 426 #region 輔助方法 427 428 /// <summary> 429 /// 確保當前集合的容量,不小於指定的值。 430 /// </summary> 431 /// <param name="min">指定一個值,此方法會確保當前集合的容量不小於此值。</param> 432 private void EnsureCapacity(int min) 433 { 434 if (this.items.Length < min) 435 { 436 int num = this.items.Length; 437 if (num < min) 438 { 439 num = min; 440 } 441 this.Capacity = num; 442 } 443 } 444 #endregion 445 } 446 }View Code