首页 > 代码库 > C# 索引器,实现IEnumerable接口的GetEnumerator()方法

C# 索引器,实现IEnumerable接口的GetEnumerator()方法

当自定义类需要实现索引时,可以在类中实现索引器。

用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 =http://www.mamicode.com/ values[i];
31                 this[i].StringValue =http://www.mamicode.com/ 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 =http://www.mamicode.com/ values[i];
44                 this[i].StringValue =http://www.mamicode.com/ 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 =http://www.mamicode.com/ values[i];
57                 this[i].StringValue =http://www.mamicode.com/ 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 = http://www.mamicode.com/"学号";
 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 =http://www.mamicode.com/= 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

 

C# 索引器,实现IEnumerable接口的GetEnumerator()方法