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

Posted 云栾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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         /// cells
 8         /// </summary>
 9         private Cell[] _cells;
10 
11         /// <summary>
12         /// 获取Row中的Cell数
13         /// </summary>
14         public int Length { get; private set; }
15 
16         /// <summary>
17         /// 索引
18         /// </summary>
19         public Cell this[int column]
20         {
21             get
22             {
23                 return this[column];
24             }
25         }
26         /// <summary>
27         ///28         /// </summary>
29         /// <param name="values"></param>
30         public Row(object[] values)
31         {
32             this.Length = values.Length;
33             this._cells = new Cell[this.Length];
34             for (int i = 0; i < this.Length; i++)
35             {
36                 _cells[i].Value = values[i];
37                 _cells[i].StringValue = Convert.ToString(values[i]);
38             }
39         }
40         /// <summary>
41         ///42         /// </summary>
43         /// <param name="values"></param>
44         public Row(string[] values)
45         {
46             this.Length = values.Length;
47             this._cells = new Cell[this.Length];
48             for (int i = 0; i < this.Length; i++)
49             {
50                 _cells[i].Value = values[i];
51                 _cells[i].StringValue = values[i];
52             }
53         }
54         /// <summary>
55         ///56         /// </summary>
57         /// <param name="values"></param>
58         public Row(int[] values)
59         {
60             this.Length = values.Length;
61             this._cells = new Cell[this.Length];
62             for (int i = 0; i < this.Length; i++)
63             {
64                 _cells[i].Value = values[i];
65                 _cells[i].StringValue = values[i].ToString();
66             }
67         }
68     }
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 >= 深入浅出-探究C#中的IEnumerableIEnumeratorYield

从C#走进Python迭代器

GetEnumerator();yield

C#知识点-枚举器和迭代器

C# 迭代器

C# 使用IENUMERABLE,YIELD