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     }

 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     }

这时候,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     }

但是,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         }

这样,在调用的时候就能使用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 }

时间: 2024-10-12 09:14:01

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

IEnumerable接口的扩展方法

/// <summary>/// IEnumerable接口的扩展方法,支持它的实现类是List的情况/// </summary>using System.Collections.Generic;public static class IEnumerableExtensions{ /// <summary> /// 向集合中添加元素 /// </summary> /// <typeparam name="T"></typ

接口、索引器、Foreach的本质(学习笔记)

接口 什么是接口? 接口代表一种能力,和抽象类类似但比抽象类的抽象程度更高! 接口的定义: 1 public interface IEat//定义一个接口 2 { 3 void Eat(string food);//为该接口定义一种能力 4 } 接口的定义 从上边的例子中我们可以看到,接口中的方法是没有方法体的甚至连访问修饰符都没有.而且在接口中只能有方法.属性.索引器及事件! 接口的使用: 1 public class Dog:IEat //Dog类实现IEat接口 2 { 3 //Dog类实

C#中索引器的作用和实现。

官方描述:索引器允许类或结构的实例就像数组一样进行索引.索引器形态类似于,不同之处在于它们的取值函数采用参数. 这一功能在创建集合类的场合特别有用,而在其他某些情况下,比如处理大型文件或者抽象有些资源等,能让类具有类似数组行为也是非常有用的. 大致结构: <modifier><return type> this [argument list] { get{//读} set{//写} } 其中: modifier:修饰符,如:public,private,protected this

描述一下C#中索引器的实现过程,是否只能根据数字进行索引?

不是.可以用任意类型. 索引器是一种特殊的类成员,它能够让对象以类似数组的方式来存取,使程序看起来更为直观,更容易编写. 1.索引器的定义 C#中的类成员可以是任意类型,包括数组和集合.当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作. 定义索引器的方式与定义属性有些类似,其一般形式如下: [修饰符] 数据类型 this[索引类型 index] { get{//获得属性的代码} set{ //设置属性的代码} } 修饰符包括 public,protected,priva

[转]C#索引器

索引器是一种特殊的类成员,它能够让对象以类似数组的方式来存取,使程序看起来更为直观,更容易编写. 1.索引器的定义 C#中的类成员可以是任意类型,包括数组和集合.当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作. 定义索引器的方式与定义属性有些类似,其一般形式如下: [修饰符] 数据类型 this[索引类型 index] { get{//获得属性的代码} set{ //设置属性的代码} } 修饰符包括 public,protected,private,internal,

索引器 C#

概述 索引器允许类或结构的实例就像数组一样进行索引. 索引器类似于属性,不同之处在于它们的访问器采用参数. 在下面的示例中,定义了一个泛型类,并为其提供了简单的 get 和 set 访问器方法(作为分配和检索值的方法). Program 类为存储字符串创建了此类的一个实例. Code 1 class SampleCollection<T> 2 { 3 // Declare an array to store the data elements. 4 private T[] arr = new

foreach遍历访问的对象必须实现IEnumerable 或声明GetEnumerator

需要实现一个对象为可遍历的对象,必须实现IEnumerable或声明GetEnumerator 方法,其中,IEnumerable 不是必须实现,但是GetEnumerator 方法则必须声明: 例如,先声明一个Item类,该类用于遍历的实体 //先声明一个Item的对象,用于遍历的实体对象 public class Item { public int Id; public string Name; public int Price; public Item(int id, string nam

索引器的真面目

今天在一个类中定义了一个索引器,但是再定义一个叫Item的属性的时候发现编译器报错: 1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Person p = new Person(); 8 p["name"] = "hello"; 9 Console.WriteLine(p[3]); 10 Console.WriteLine(p["name&qu

Asp.Net中索引器的用法

索引器定义类似于属性,但其功能与属性并不相同.索引器提供一种特殊的方法编写get和set访问器.属性可以像访问字段一样访问对象的数据,索引器可以使用户像访问数组一样访问类成员. 一.索引器特性 1.get 访问器返回值.set 访问器分配值.2.this 关键字用于定义索引器. 3.value 关键字用于定义由 set 索引器分配的值.4.索引器不必根据整数值进行索引,由您决定如何定义特定的查找机制. 5.索引器可被重载.6.索引器可以有多个形参,例如当访问二维数组时.7.索引器使得对象可按照与